home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 October: Technology Seed / ADC Seed CD - October 1999.toast / FireWire / FireWire_2.1_SDK_DR3 / Source / FWIM / PeleFWIM / PeleFWIM.c next >
Encoding:
Text File  |  1999-05-17  |  256.9 KB  |  8,411 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        PeleFWIM.c
  3.  
  4.     Contains:    FireWire interface module software for Pele-based 1394 cards.
  5.  
  6.     Written by:    Eric W. Anderson
  7.  
  8.     Copyright:    © 1997 by Apple Computer, Inc., all rights reserved.
  9.                 FireWire is a registered trademark of Apple Computer, Inc.,
  10.                 in the United States and other countries.
  11.                 This file is Apple Confidential.  Distribution is restricted.
  12.  
  13.     Change History (most recent first):
  14.  
  15.        <FW2>      6/5/97    EA        Fill in contains and written by fields.
  16.        <FW1>      6/5/97    EA        first checked in
  17.  
  18. */
  19.  
  20. // This was adapted from LynxFWIM sample code and earlier Pele FWIM work.
  21. // Asynch is now spelled consistently to match Isoch, except where the Pele
  22. // spec says "async".  (e.g. asyncRetryCnt)
  23.  
  24. // Still need to clean up usage of Lynx terminology such as "PCL".
  25. // Substitute "DBDMA" or "Descriptor" when you see "PCL".
  26.  
  27. // Major items not completed:
  28. //    Honor IRDMA start-on-cycle requests (now we just start ASAP)
  29. //    Honor SendPacketWithHeaderStartOp (returns error currently)
  30. //    Find a way to make ReceivePacketOp work (returns error)
  31. //    Make VM work in all cases (currently requires contiguous pages)
  32. //    Make IRDMA safe if callProc/etc. happens in both channels before first packet.
  33. //    Read serial (or other) EEPROM to learn globally unique ID (GUID)
  34. //    Set contender bit correctly if we can
  35. //    Sometimes the ITDMA gets stuck active.  Stop more cleanly to avoid this. (not just run=0)
  36. //    Fix cycleTooLong causing the cycle master state machine to jam on resets.
  37. //    Would be nice to use the ATRetry hardware.
  38. //    Should correctly process acks, and should not busy-wait for acks.
  39.  
  40. // There are #defines below in the Driver Descriptor that select some vendor-
  41. // specific PCI identification codes.  Be sure to make any needed changes.
  42. // If you're going to ship a product, call it something other than PeleFWIM.
  43. // For example, VendorFWIM or VendorPeleFWIM, where Vendor is your name.
  44. // All other vendor-specific options are located here:
  45.  
  46.  
  47. // Define this if your Pele is an older design that does not support
  48. // the phyRegRcvd interrupt (bit 30 in the various interrupt registers).
  49.  
  50. //#define PELE_NO_PHY_REG_RCVD
  51.  
  52.  
  53. // Define this if your Pele IRDMA cannot perform startOnEvent 00 (ie, set run
  54. // bit to start).  This will cause us to use event 11 instead (ie, pretend that
  55. // the condition was already satisfied), which seems to work on such Peles.
  56.  
  57. //#define PELE_NO_START_ON_RUN
  58.  
  59.  
  60. // There are no #defines for LinkOnEnable and EnableAT, because using those
  61. // features on Peles that don't implement them seems to be harmless.
  62.  
  63.  
  64.  
  65. // General Pele tips and notes
  66. //
  67. // Pele interrupts are edge-triggered.  If you clear an interrupt without clearing the
  68. // condition that caused it, you may not get another interrupt.  For example, cycleTooLong
  69. // will stay high until you turn the cycle master off and then back on, but if you clear
  70. // this interrupt without doing that, you won't get any more of them, even though the
  71. // cycle master state machine is still stuck.
  72. //
  73. // STORE_QUAD can take a byte or word, but it always writes 32 bits, zero-padded if needed.
  74. //
  75. // On some Peles, starting the IRDMA by setting startOnEvent to 3 may cause stopOnEvent to
  76. // also go to 3, thus stopping the IRDMA.  Use the above #define only if you have to.
  77. //
  78. // As with any 1394 Link, you should avoid touching registers when possible.  For example,
  79. // don't poll some register in a tight loop while waiting for DMA to finish.  All of those
  80. // reads will slow down the DMA.
  81.  
  82. #include <Types.h>
  83. #include <Errors.h>
  84. #include <Devices.h>
  85. #include <Interrupts.h>
  86. #include <PCI.h>
  87. #include <DriverServices.h>
  88. #include <FireWire.h>
  89. #include <PeleFWIM.h>
  90. /*zzz*/
  91. #include <stdio.h>
  92. char  debugStr[256];
  93. pascal void FWDebugStr(
  94.     ConstStr255Param            debuggerMsg)
  95. {
  96. #ifdef FW_DEBUG_BUILD
  97. #if FW_DEBUG_BUILD
  98.     DebugStr (debuggerMsg);
  99. #endif
  100. #endif
  101. }
  102. /*zzz*/
  103.  
  104. // Define this to check for Logical != Physical (use with VM off)
  105. // Warning, not fully implemented in PeleFWIM (see LynxFWIM)
  106. //#define PeleVMDebug
  107.  
  108. // Define this to enable sending diagnostic messages to FireBug
  109. // Warning, not fully implemented in PeleFWIM (see LynxFWIM)
  110. //#define PeleFireBug
  111.  
  112. #ifdef PeleFireBug
  113. char  fireBug[256];
  114. #endif
  115.  
  116. ////////////////////////////////////////////////////////////////////////////////
  117. //
  118. // Internal procedure prototypes.
  119. //
  120.  
  121. static OSStatus    PeleFWIMInitialize (
  122.     FWIMInitializeParamsPtr        pFWIMInitializeParams);
  123.  
  124. static OSStatus    PeleFWIMFinalize (
  125.     FWIMFinalizeParamsPtr        pFWIMFinalizeParams);
  126.  
  127. static OSStatus    PeleFWIMPollInterrupts (
  128.     FWIMPollInterruptsParamsPtr    pFWIMPollInterruptsParams);
  129.  
  130. static OSStatus    PeleFWIMGetRegisterBaseAddress (
  131.     PeleFWIMDataPtr                pPeleFWIMData);
  132.  
  133. static OSStatus    PeleFWIMInstallInterruptHandler (
  134.     PeleFWIMDataPtr                pPeleFWIMData);
  135.  
  136. static UInt16 PeleFWIMcrc16(
  137.     UInt32                        *data,
  138.     UInt32                        count);
  139.     
  140. static OSStatus    PeleFWIMFullReset(
  141.     PeleFWIMDataPtr                pPeleFWIMData);
  142.  
  143. static OSStatus    PeleFWIMExceptionHandler (
  144.     ExceptionInformationPowerPC    *theException);
  145.  
  146. static InterruptMemberNumber    PeleFWIMInterruptHandler (
  147.     InterruptSetMember            interruptSet,
  148.     void                        *interruptRefCon,
  149.     UInt32                        interruptCount);
  150.  
  151. static OSStatus    PeleFWIMDispatchInterrupts (
  152.     PeleFWIMDataPtr                pPeleFWIMData);
  153.  
  154. static void PeleFWIMHandleDMAARInterrupt(
  155.     PeleFWIMDataPtr                pPeleFWIMData);
  156.  
  157. static void PeleFWIMHandleDMAIRAInterrupt(
  158.     PeleFWIMDataPtr                pPeleFWIMData);
  159.  
  160. static void PeleFWIMHandleDMAITAInterrupt(
  161.     PeleFWIMDataPtr                pPeleFWIMData);
  162.  
  163. static void    PeleFWIMHandleResetInterrupt (
  164.     PeleFWIMDataPtr                pPeleFWIMData);
  165.  
  166. #ifndef PELE_NO_PHY_REG_RCVD
  167. static void    PeleFWIMHandlePhyRegRcvdInterrupt (
  168.     PeleFWIMDataPtr                pPeleFWIMData);
  169. #endif
  170.  
  171. static void PeleFWIMHandleMiscInterrupt(
  172.     PeleFWIMDataPtr                pPeleFWIMData);
  173.  
  174. static OSStatus PeleFWIMResetBus (
  175.     FWIMCommandParamsPtr        pFWIMCommandParams,
  176.     UInt32                        *pCommandAcceptance);
  177.  
  178. static OSStatus PeleFWIMSetContenderBit (
  179.     FWIMCommandParamsPtr        pFWIMCommandParams,
  180.     UInt32                        *pCommandAcceptance);
  181.  
  182. static OSStatus PeleFWIMClearContenderBit (
  183.     FWIMCommandParamsPtr        pFWIMCommandParams,
  184.     UInt32                        *pCommandAcceptance);
  185.  
  186. static OSStatus    PeleFWIMEnableCycleMaster (
  187.     FWIMCommandParamsPtr        pFWIMCommandParams,
  188.     UInt32                        *pCommandAcceptance);
  189.  
  190. static OSStatus    PeleFWIMDisableCycleMaster (
  191.     FWIMCommandParamsPtr        pFWIMCommandParams,
  192.     UInt32                        *pCommandAcceptance);
  193.  
  194. static OSStatus    PeleFWIMSetRootHoldoffBit (
  195.     FWIMCommandParamsPtr        pFWIMCommandParams,
  196.     UInt32                        *pCommandAcceptance);
  197.  
  198. static OSStatus    PeleFWIMClearRootHoldoffBit (
  199.     FWIMCommandParamsPtr        pFWIMCommandParams,
  200.     UInt32                        *pCommandAcceptance);
  201.  
  202. static OSStatus    PeleFWIMGetUniqueID (
  203.     FWIMGetUniqueIDParamsPtr    pFWIMGetUniqueIDParams,
  204.     UInt32                        *pCommandAcceptance);
  205.  
  206. static OSStatus    PeleFWIMSendLinkOnPacket (
  207.     FWIMSendPhyPacketParamsPtr    pFWIMSendPhyPacketParams,
  208.     UInt32                        *pCommandAcceptance);
  209.  
  210. static OSStatus    PeleFWIMSendPhyConfigurationPacket (
  211.     FWIMSendPhyPacketParamsPtr    pFWIMSendPhyPacketParams,
  212.     UInt32                        *pCommandAcceptance);
  213.  
  214. static void    PeleFWIMWritePhyRegister (
  215.     PeleRegistersPtr            pLinkRegs,
  216.     UInt8                        regAddress,
  217.     UInt8                        regData);
  218.  
  219. static UInt8    PeleFWIMReadPhyRegister (
  220.     PeleFWIMDataPtr                pPeleFWIMData,
  221.     PeleRegistersPtr            pLinkRegs,
  222.     UInt8                        regAddress);
  223.  
  224. static void PeleFWIMAddAsynchRxDMA (
  225.     PeleAsynchRxDMADataPtr        pPeleAsynchRxDMAData);
  226.  
  227. static void PeleFWIMCreateAsynchRxDMAProgram (
  228.     PeleFWIMDataPtr                pPeleFWIMData);
  229.  
  230. static void PeleFWIMCreateAsynchRxOverflowDMASegment (
  231.     PeleFWIMDataPtr                pPeleFWIMData);
  232.  
  233. static void PeleFWIMStartAsynchRxDMAProgram (
  234.     PeleFWIMDataPtr                pPeleFWIMData,
  235.     PeleAsynchRxDMADataPtr        pPeleAsynchRxDMAData);
  236.  
  237. static void PeleFWIMAddAsynchTxDMA (
  238.     PeleAsynchTxDMADataPtr        pTxDMAData);
  239.  
  240. static void PeleFWIMCreateAsynchTxDoneDMASegment (
  241.     PeleFWIMDataPtr                pPeleFWIMData);
  242.  
  243. static void PeleFWIMCreateAsynchTxDataDMA (
  244.     PeleFWIMDataPtr                pPeleFWIMData);
  245.  
  246. static void PeleFWIMStartAsynchTxDMAProgram (
  247.     PeleFWIMDataPtr                pPeleFWIMData,
  248.     PeleAsynchTxDMADataPtr        pStartTxDMAData);
  249.  
  250. static OSStatus PeleFWIMWriteAT(
  251.     PeleFWIMDataPtr                pPeleFWIMData,
  252.     UInt32                        speed,
  253.     UInt32                        baseCount,
  254.     UInt32                        data1,
  255.     UInt32                        data2,
  256.     UInt32                        data3,
  257.     UInt32                        data4,
  258.     UInt32                        extCount,
  259.     UInt32                        *extData);
  260.  
  261. static OSStatus    PeleFWIMBuildAsynchTxDMA (
  262.     PeleFWIMDataPtr                pPeleFWIMData,
  263.     PeleAsynchTxDMADataPtr        pTxDMAData,
  264.     IOPreparationID                *pIOPreparationID,
  265.     Ptr                            buffer1,
  266.     UInt32                        size1,
  267.     Ptr                            buffer2,
  268.     UInt32                        size2);
  269.  
  270. static OSStatus    PeleFWIMRead (
  271.     FWIMAsynchCommandParamsPtr    pFWIMAsynchCommandParams,
  272.     UInt32                        *pCommandAcceptance);
  273.  
  274. static OSStatus    PeleFWIMReadResponse (
  275.     FWIMAsynchResponseCommandParamsPtr
  276.                                 pFWIMAsynchResponseCommandParams,
  277.     UInt32                        *pCommandAcceptance);
  278.  
  279. static OSStatus    PeleFWIMWriteTimer (
  280.     void                        *p1,
  281.     void                        *p2);
  282.  
  283. static OSStatus    PeleFWIMWrite (
  284.     FWIMAsynchCommandParamsPtr    pFWIMAsynchCommandParams,
  285.     UInt32                        *pCommandAcceptance);
  286.  
  287. static OSStatus    PeleFWIMWriteResponse (
  288.     FWIMAsynchResponseCommandParamsPtr
  289.                                 pFWIMAsynchResponseCommandParams,
  290.     UInt32                        *pCommandAcceptance);
  291.  
  292. static OSStatus    PeleFWIMLock (
  293.     FWIMAsynchCommandParamsPtr    pFWIMAsynchCommandParams,
  294.     UInt32                        *pCommandAcceptance);
  295.  
  296. static OSStatus    PeleFWIMLockResponse (
  297.     FWIMAsynchResponseCommandParamsPtr
  298.                                 pFWIMAsynchResponseCommandParams,
  299.     UInt32                        *pCommandAcceptance);
  300.  
  301. static Boolean    PeleFWIMIsCompilableDCLProgram (
  302.     DCLProgramID                dclProgramID);
  303.  
  304. static OSStatus PeleFWIMCompileDCLProgram (
  305.     PeleFWIMDataPtr                pPeleFWIMData,
  306.     DCLProgramID                dclProgramID,
  307.     UInt32                        dmaChannelNum,
  308.     UInt32                        channelNum,
  309.     UInt32                        speed);
  310.  
  311. static OSStatus PeleFWIMAddDCL (
  312.     PeleDMABuildStatePtr        pPeleDMABuildState,
  313.     DCLCommandPtr                pDCLCommand);
  314.  
  315. static OSStatus PeleFWIMAddReceivePacketStartDCL (
  316.     PeleDMABuildStatePtr        pPeleDMABuildState,
  317.     DCLCommandPtr                pDCLCommand);
  318.  
  319. static OSStatus PeleFWIMAddReceivePacketDCL (
  320.     PeleDMABuildStatePtr        pPeleDMABuildState,
  321.     DCLCommandPtr                pDCLCommand);
  322.  
  323. static OSStatus PeleFWIMAddSendPacketStartDCL (
  324.     PeleDMABuildStatePtr        pPeleDMABuildState,
  325.     DCLCommandPtr                pDCLCommand);
  326.  
  327. static OSStatus PeleFWIMAddSendPacketWithHeaderStartDCL (
  328.     PeleDMABuildStatePtr        pPeleDMABuildState,
  329.     DCLCommandPtr                pDCLCommand);
  330.  
  331. static OSStatus PeleFWIMAddSendPacketDCL (
  332.     PeleDMABuildStatePtr        pPeleDMABuildState,
  333.     DCLCommandPtr                pDCLCommand);
  334.  
  335. static OSStatus PeleFWIMAddCallProcDCL (
  336.     PeleDMABuildStatePtr        pPeleDMABuildState,
  337.     DCLCommandPtr                pDCLCommand);
  338.  
  339. static OSStatus PeleFWIMAddJumpDCL (
  340.     PeleDMABuildStatePtr        pPeleDMABuildState,
  341.     DCLCommandPtr                pDCLCommand);
  342.  
  343. static OSStatus PeleFWIMAddUpdateDCLListDCL (
  344.     PeleDMABuildStatePtr        pPeleDMABuildState,
  345.     DCLCommandPtr                pDCLCommand);
  346.  
  347. static OSStatus PeleFWIMAddTimeStampDCL (
  348.     PeleDMABuildStatePtr        pPeleDMABuildState,
  349.     DCLCommandPtr                pDCLCommand);
  350.  
  351. static OSStatus PeleFWIMAddStopDCL(
  352.     PeleDMABuildStatePtr        pPeleDMABuildState);
  353.  
  354. static OSStatus    PeleFWIMDMAStart (
  355.     PeleFWIMDataPtr                pPeleFWIMData,
  356.     PeleDMABuildStatePtr        *ppPeleDMABuildState,
  357.     PeleDMAPtr                    *ppStartDMA);
  358.  
  359. static OSStatus PeleFWIMAddLabelDCL(
  360.     PeleDMABuildStatePtr        pPeleDMABuildState,
  361.     DCLCommandPtr                pDCLCommand);
  362.  
  363. static OSStatus PeleFWIMAddSetTagSyncBitsDCL (
  364.     PeleDMABuildStatePtr        pPeleDMABuildState,
  365.     DCLCommandPtr                pDCLCommand);
  366.  
  367. static OSStatus    PeleFWIMResolveDCLLabel (
  368.     DCLLabelPtr                    pDCLLabel);
  369.  
  370. static OSStatus        PeleFWIMDCLCompilerNotification (
  371.     DCLProgramID                dclProgramID,
  372.     UInt32                        notificationType,
  373.     DCLCommandPtr                *dclCommandList,
  374.     UInt32                        numDCLCommands);
  375.  
  376. static OSStatus        PeleFWIMDCLCompilerUpdateNotification (
  377.     DCLProgramID                dclProgramID,
  378.     DCLCommandPtr                *dclCommandList,
  379.     UInt32                        numDCLCommands);
  380.  
  381. static OSStatus        PeleFWIMUpdateDCLTimeStamp (
  382.     DCLCommandPtr                pDCLCommand);
  383.  
  384. static OSStatus        PeleFWIMUpdateDCLReceivePacketStart (
  385.     DCLCommandPtr                pDCLCommand);
  386.  
  387. static OSStatus        PeleFWIMDCLCompilerModifyNotification (
  388.     DCLProgramID                dclProgramID,
  389.     DCLCommandPtr                *dclCommandList,
  390.     UInt32                        numDCLCommands);
  391.  
  392. static OSStatus    PeleFWIMAllocateDMABuildState (
  393.     PeleFWIMDataPtr                pPeleFWIMData,
  394.     PeleDMABuildStatePtr        *ppPeleDMABuildState);
  395.  
  396. static OSStatus    PeleFWIMAllocateDMA (
  397.     PeleDMABuildStatePtr        pPeleDMABuildState,
  398.     PeleDMAPtr                    *ppDMA,
  399.     PhysicalAddress                *ppDMAPhys,
  400.     UInt32                        count);
  401.  
  402. static void PeleFWIMDeallocateDMAPools (
  403.     PeleDMAPoolDataPtr            pPeleDMAPoolDataList);
  404.  
  405. static void    PeleFWIMRunDCLProgram (
  406.     PeleIsochPortDataPtr        pPeleIsochPortData,
  407.     Ptr                            packetBuffer,
  408.     UInt32                        packetSize,
  409.     DCLCommandPtr                *ppDCLCommand);
  410.  
  411. static void    PeleFWIMDCLReceivePacketStart (
  412.     Ptr                            *pPacketBuffer,
  413.     UInt32                        *pPacketSize,
  414.     DCLCommandPtr                *ppDCLCommand,
  415.     Boolean                        *pWaitForPacket);
  416.  
  417. static void    PeleFWIMDCLReceiveBuffer (
  418.     Ptr                            *pPacketBuffer,
  419.     UInt32                        *pPacketSize,
  420.     DCLCommandPtr                *ppDCLCommand,
  421.     Boolean                        *pWaitForPacket);
  422.  
  423. static OSStatus PeleFWIMAllocateIsochPort (
  424.     FWIMAllocateIsochPortParamsPtr
  425.                                 pFWIMAllocateIsochPortParams,
  426.     UInt32                        *pCommandAcceptance);
  427.  
  428. static OSStatus PeleFWIMReleaseIsochPort (
  429.     FWIMReleaseIsochPortParamsPtr
  430.                                 pFWIMReleaseIsochPortParams,
  431.     UInt32                        *pCommandAcceptance);
  432.  
  433. static OSStatus _PeleFWIMReleaseIsochPort (
  434.     PeleFWIMDataPtr                pPeleFWIMData,
  435.     PeleIsochPortDataPtr        pPeleIsochPortData);
  436.  
  437. static OSStatus PeleFWIMStartIsochPort (
  438.     FWIMIsochPortControlParamsPtr
  439.                                 pFWIMIsochPortControlParams,
  440.     UInt32                        *pCommandAcceptance);
  441.  
  442. static OSStatus PeleFWIMStopIsochPort (
  443.     FWIMIsochPortControlParamsPtr
  444.                                 pFWIMIsochPortControlParams,
  445.     UInt32                        *pCommandAcceptance);
  446.  
  447. static OSStatus PeleFWIMStartTalkingDCLProgram (
  448.     DCLProgramID                dclProgramID);
  449.  
  450. static OSStatus PeleFWIMStartListeningDCLProgram (
  451.     DCLProgramID                dclProgramID);
  452.  
  453. static OSStatus PeleFWIMStopTalkingDCLProgram (
  454.     DCLProgramID                dclProgramID);
  455.  
  456. static OSStatus PeleFWIMStopListeningDCLProgram (
  457.     DCLProgramID                dclProgramID);
  458.  
  459. static OSStatus PeleFWIMReleaseDCLProgram (
  460.     DCLProgramID                dclProgramID);
  461.  
  462. static OSStatus    PeleFWIMReadRequestTimeoutHandler (
  463.     void                        *p1,
  464.     void                        *p2);
  465.  
  466. static OSStatus    PeleFWIMWriteRequestTimeoutHandler (
  467.     void                        *p1,
  468.     void                        *p2);
  469.  
  470. static OSStatus    PeleFWIMLockRequestTimeoutHandler (
  471.     void                        *p1,
  472.     void                        *p2);
  473.  
  474. static void    PeleFWIMDMAARDeferredTask(
  475.     void                        *p1,
  476.     void                        *p2);
  477.     
  478. static void    PeleFWIMDMAIsochReceiveDeferredTask(
  479.     void                        *p1,
  480.     void                        *p2);
  481.     
  482. static void    PeleFWIMDMAIsochTransmitDeferredTask(
  483.     void                        *p1,
  484.     void                        *p2);
  485.     
  486. static void    PeleFWIMResetDeferredTask (
  487.     void                        *p1,
  488.     void                        *p2);
  489.  
  490. static OSStatus    PeleFWIMDelayedReset(
  491.     void                        *p1,
  492.     void                        *p2);
  493.  
  494. static void    PeleFWIMMiscInterruptDeferredTask (
  495.     void                        *p1,
  496.     void                        *p2);
  497.  
  498. static OSStatus    PeleFWIMAckSecondaryInterruptHandler (
  499.     void                        *p1,
  500.     void                        *p2);
  501.  
  502. static void PeleFWIMProcessPacket (
  503.     PeleFWIMDataPtr                pPeleFWIMData,
  504.     PeleAsynchRxDMADataPtr        pRxDMAData,
  505.     Ptr                            packetBuffer,
  506.     UInt32                        packetSize);
  507.  
  508. static void    PeleFWIMProcessSelfIDPacket (
  509.     PeleFWIMDataPtr                pPeleFWIMData,
  510.     PeleAsynchRxDMADataPtr        pRxDMAData,
  511.     Ptr                            packetBuffer,
  512.     UInt32                        packetSize);
  513.  
  514. static void    PeleFWIMProcessWriteQuadletPacket (
  515.     PeleFWIMDataPtr                pPeleFWIMData,
  516.     PeleAsynchRxDMADataPtr        pRxDMAData,
  517.     Ptr                            packetBuffer,
  518.     UInt32                        packetSize);
  519.  
  520. static void    PeleFWIMProcessWriteQuadletRequestCompletionProc (
  521.     FWIMProcessParamsPtr        pFWIMProcessParams);
  522.  
  523. static void    PeleFWIMProcessWriteBlockPacket (
  524.     PeleFWIMDataPtr                pPeleFWIMData,
  525.     PeleAsynchRxDMADataPtr        pRxDMAData,
  526.     Ptr                            packetBuffer,
  527.     UInt32                        packetSize);
  528.  
  529. static void    PeleFWIMProcessWriteBlockRequestCompletionProc (
  530.     FWIMProcessParamsPtr        pFWIMProcessParams);
  531.  
  532. static void    PeleFWIMProcessWriteResponsePacket (
  533.     PeleFWIMDataPtr                pPeleFWIMData,
  534.     PeleAsynchRxDMADataPtr        pRxDMAData,
  535.     Ptr                            packetBuffer,
  536.     UInt32                        packetSize);
  537.  
  538. static void    PeleFWIMProcessReadQuadletPacket (
  539.     PeleFWIMDataPtr                pPeleFWIMData,
  540.     PeleAsynchRxDMADataPtr        pRxDMAData,
  541.     Ptr                            packetBuffer,
  542.     UInt32                        packetSize);
  543.  
  544. static void    PeleFWIMProcessReadQuadletRequestCompletionProc (
  545.     FWIMProcessParamsPtr        pFWIMProcessParams);
  546.  
  547. static void    PeleFWIMProcessReadBlockPacket (
  548.     PeleFWIMDataPtr                pPeleFWIMData,
  549.     PeleAsynchRxDMADataPtr        pRxDMAData,
  550.     Ptr                            packetBuffer,
  551.     UInt32                        packetSize);
  552.  
  553. static void    PeleFWIMProcessReadBlockRequestCompletionProc (
  554.     FWIMProcessParamsPtr        pFWIMProcessParams);
  555.  
  556. static void    PeleFWIMProcessReadQuadletResponsePacket (
  557.     PeleFWIMDataPtr                pPeleFWIMData,
  558.     PeleAsynchRxDMADataPtr        pRxDMAData,
  559.     Ptr                            packetBuffer,
  560.     UInt32                        packetSize);
  561.  
  562. static void    PeleFWIMProcessReadBlockResponsePacket (
  563.     PeleFWIMDataPtr                pPeleFWIMData,
  564.     PeleAsynchRxDMADataPtr        pRxDMAData,
  565.     Ptr                            packetBuffer,
  566.     UInt32                        packetSize);
  567.  
  568. static void    PeleFWIMProcessLockPacket (
  569.     PeleFWIMDataPtr                pPeleFWIMData,
  570.     PeleAsynchRxDMADataPtr        pRxDMAData,
  571.     Ptr                            packetBuffer,
  572.     UInt32                        packetSize);
  573.  
  574. static void    PeleFWIMProcessLockRequestCompletionProc (
  575.     FWIMProcessParamsPtr        pFWIMProcessParams);
  576.  
  577. static void    PeleFWIMProcessLockResponsePacket (
  578.     PeleFWIMDataPtr                pPeleFWIMData,
  579.     PeleAsynchRxDMADataPtr        pRxDMAData,
  580.     Ptr                            packetBuffer,
  581.     UInt32                        packetSize);
  582.  
  583. #ifdef PeleFireBug
  584. static void PeleFWIMFireBugMsg (
  585.     PeleFWIMDataPtr                pPeleFWIMData,
  586.     char                         *msg);
  587. #endif
  588.  
  589.  
  590. ////////////////////////////////////////////////////////////////////////////////
  591. //
  592. // The driver descriptor.
  593. //
  594.  
  595. // Define one of these or edit the driver descriptor as needed.
  596. // These are not used elsewhere in the code, except for PELE_VENDOR_NONE
  597. // which will cause a compiler warning (see below).
  598.  
  599. //#define PELE_VENDOR_A
  600. //#define PELE_VENDOR_F
  601. //#define PELE_VENDOR_S1
  602. //#define PELE_VENDOR_S2
  603. #define PELE_VENDOR_NONE
  604.  
  605.  
  606. DriverDescription                TheDriverDescription =
  607. {
  608.     kTheDescriptionSignature,
  609.     kInitialDriverDescriptor,
  610.     {
  611. #ifdef PELE_VENDOR_A
  612.         "\ppci9004,8940",
  613. #endif
  614. #ifdef PELE_VENDOR_F
  615.         "\ppci12bf,0",
  616. #endif
  617. #ifdef PELE_VENDOR_S1
  618.         "\ppci1000,301",
  619. #endif
  620. #ifdef PELE_VENDOR_S2
  621.         "\ppci104d,8009",
  622. #endif
  623. #ifdef PELE_VENDOR_NONE
  624.         "\ppciNULL,VOID",
  625. #endif
  626.         1, 0, finalStage, 1,
  627.     },
  628.     {
  629.         kDriverIsUnderExpertControl,
  630.         "\pPeleFWIM",                    // RENAME THIS - see preamble comments
  631.     },
  632.  
  633.     1,
  634.     kServiceCategoryFWIM,
  635.     0,
  636.     1,0,0,0
  637. };
  638.  
  639.  
  640. // This hack will cause the compiler to warn about an unused variable or
  641. // an uninitialized variable (or both), at least in the MPW environment
  642. // used by Apple.  You are supposed to get a clue from this that you need
  643. // to define the PCI name in the Driver Descriptor (above).
  644.  
  645. #ifdef PELE_VENDOR_NONE
  646. static UInt32 PeleFWIM_Compiler_warning_hack ()
  647. {
  648.     UInt32 WARNING___NO_PELE_VENDOR_DEFINED;
  649.     UInt32 _WARNING___NO_PELE_VENDOR_DEFINED;
  650.     return _WARNING___NO_PELE_VENDOR_DEFINED;
  651. }
  652. #endif
  653.  
  654.  
  655. ////////////////////////////////////////////////////////////////////////////////
  656. //
  657. // The plug in dispatch table.
  658. //
  659.  
  660. FWIMPluginDispatchTable            ThePluginDispatchTable =
  661. {
  662.     kFWIMPluginVersion,
  663.     PeleFWIMInitialize,
  664.     PeleFWIMFinalize,
  665.     PeleFWIMPollInterrupts,
  666.     PeleFWIMSendLinkOnPacket,
  667.     PeleFWIMSendPhyConfigurationPacket,
  668.     PeleFWIMRead,
  669.     PeleFWIMReadResponse,
  670.     PeleFWIMWrite,
  671.     PeleFWIMWriteResponse,
  672.     PeleFWIMLock,
  673.     PeleFWIMLockResponse,
  674.     PeleFWIMAllocateIsochPort,
  675.     PeleFWIMReleaseIsochPort,
  676.     PeleFWIMStartIsochPort,
  677.     PeleFWIMStopIsochPort,
  678.     PeleFWIMResetBus,
  679.     PeleFWIMSetContenderBit,
  680.     PeleFWIMClearContenderBit,
  681.     PeleFWIMEnableCycleMaster,
  682.     PeleFWIMDisableCycleMaster,
  683.     PeleFWIMSetRootHoldoffBit,
  684.     PeleFWIMClearRootHoldoffBit,
  685.     PeleFWIMGetUniqueID
  686. };
  687.  
  688.  
  689. ////////////////////////////////////////////////////////////////////////////////
  690. //
  691. // PeleFWIMInitialize
  692. //
  693. //   This is the FWIM installer proc.  It allocates the FWIM data record, gets
  694. // the register base address, installs the interrupt handler, enables the
  695. // register memory space, sets the chip up to receive selfID packets,
  696. // enables bus reset interrupts, and initiates a bus reset to get the topology
  697. // map.
  698. //zzz Clean up on error???
  699. //zzz Do we always need to initiate a bus reset???
  700. //
  701.  
  702. static OSStatus    PeleFWIMInitialize(
  703.     FWIMInitializeParamsPtr        pFWIMInitializeParams)
  704. {
  705.     PeleFWIMDataPtr                pPeleFWIMData;
  706.     RegEntryIDPtr                pFWIMRegEntryID;
  707.     Ptr                            p;
  708.     IOPreparationTable            *ioPrep;
  709.     UInt32                        pageSize, totalAlloc;
  710.     UInt32                        bufsPerPage, bufPages;
  711.     UInt32                        dmasPerPage, dmaPages;
  712.     UInt32                        doBuf, doPage, bufsDone, offset;
  713.     Ptr                            logPage, physPage;
  714.     OSStatus                    status = noErr;
  715.  
  716. //    FWDebugStr ((ConstStr255Param) "\pPeleFWIMInitialize");
  717.  
  718.     pageSize = GetLogicalPageSize ();
  719.     
  720.     // Allocate Pele FWIM data.
  721.     // Parts of this struct will be phyiscally addressed, so we need
  722.     // to make sure those parts don't straddle a page boundary.  To
  723.     // guarantee this, we put them first in the struct, and we'll
  724.     // page-align the whole struct, and map the first page.
  725.     
  726.     // Phys addressing may be moot with Pele.  It was required in Lynx.
  727.     
  728.     p = PoolAllocateResident (sizeof (PeleFWIMData) + pageSize, true);
  729.     if (p)
  730.     {
  731.         p = (Ptr) (((UInt32) p + (pageSize - 1)) & ~(pageSize - 1));    // page-align
  732.         pPeleFWIMData = (PeleFWIMDataPtr) p;
  733.         
  734.         pPeleFWIMData->pageSize = pageSize;
  735.         pPeleFWIMData->pageShift = 1;
  736.         while (pageSize >>= 1)
  737.             pPeleFWIMData->pageShift++;
  738.         pageSize = pPeleFWIMData->pageSize;
  739.         
  740.         ioPrep = &pPeleFWIMData->fwimDataIOPrep;
  741.         ioPrep->options = kIOLogicalRanges | kIOIsInput | kIOIsOutput;
  742.         ioPrep->addressSpace = kCurrentAddressSpaceID;            // default
  743.         ioPrep->granularity = 0;                                // do it all now
  744.         ioPrep->firstPrepared = 0;
  745.         ioPrep->mappingEntryCount = 1;                            // # of pages we will use
  746.         ioPrep->logicalMapping = 0;
  747.         ioPrep->physicalMapping = &pPeleFWIMData->fwimDataPhys;    // return phys addr
  748.         ioPrep->rangeInfo.range.base = (void *) pPeleFWIMData;    // first addr to map
  749.         ioPrep->rangeInfo.range.length = pageSize;                // map one page
  750.         
  751.         // there is no CheckpointIO which matches this.  It will be held down forever.
  752.         status = PrepareMemoryForIO (ioPrep);
  753.         if (status != noErr)
  754.         {
  755.             sprintf (debugStr, "FWIMData PrepMemIO status %ld    logical %08lx physical %08lx len %lx",
  756.                      (long) status,
  757.                      (long) ioPrep->rangeInfo.range.base,
  758.                      (long) pPeleFWIMData->fwimDataPhys,
  759.                      (long) ioPrep->rangeInfo.range.length);
  760.             FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  761.         }
  762.         
  763.         if (status == noErr)
  764.         {
  765.             pFWIMInitializeParams->fwimSpecificData = (UInt32) pPeleFWIMData;
  766.         }
  767.         
  768.     }
  769.     else
  770.     {
  771.         status = memFullErr;
  772.     }
  773.  
  774.     // Get notification proc and name registry ID.
  775.     if (status == noErr)
  776.     {
  777.         pPeleFWIMData->fwimID = pFWIMInitializeParams->fwimID;
  778.         pPeleFWIMData->FWIMRegEntryID = pFWIMInitializeParams->fwimRegEntryID;
  779.         pFWIMRegEntryID = &(pPeleFWIMData->FWIMRegEntryID);
  780.     }
  781.  
  782.     // Get register base address.
  783.     if (status == noErr)
  784.     {
  785.         status = PeleFWIMGetRegisterBaseAddress (pPeleFWIMData);
  786.     }
  787.  
  788.     // Note - sometimes these buffers are used to assemble response packets
  789.     // So even if only a few quads are used in receiving, the rest of the buffer
  790.     // may still be written to later (see PeleFWIMProcessReadBlockPacket, etc.)
  791.     
  792.     // Allocate asynch / self-ID buffers:
  793.     // Buffers will not span page boundaries (for now, max rcv packet fits in a page)
  794.     // and will be 32-byte aligned for best Pele performance.  To save memory, alloc
  795.     // one big buffer, prep it for I/O, and carve it up.  If marked for input, we can
  796.     // re-use it over and over with no VM upkeep.  kAsyncRxPacketBufferSize must be multiple of 32.
  797.     // PCLs are PCL-size-aligned, PCL-size is 128 and must divide the page size (easy).
  798.     
  799.     // Use a single allocation for asynch xmit/rcv buffers and xmit/rcv PCLs.  Marking
  800.     // all the memory as "input | output" may prevent some optimizations - future feature.
  801.     
  802.     // Note, because we don't span page boundaries, we don't need to request contig
  803.     // memory.  Change to ordinary allocate once it's working.  (Asynch rcv PCLs do span
  804.     // pages, fix that first)
  805.     
  806.     if (status == noErr)
  807.     {
  808.         bufsPerPage = pageSize / kAsyncRxPacketBufferSize;
  809.         bufPages = (kAsynchRxBufs + bufsPerPage - 1) / bufsPerPage;
  810.         dmasPerPage = pageSize / sizeof (PeleDMA);
  811.         dmaPages = (kAsynchRxBufs + dmasPerPage - 1) / dmasPerPage;
  812.         
  813.         totalAlloc = bufPages;                                // Space for asynch rcv bufs
  814.         totalAlloc += 1;                                    // Space for asynch xmit buf
  815.         totalAlloc += dmaPages;                                // Space for asynch rcv PCLs
  816.         totalAlloc += 1;                                    // Space for asynch xmit PCLs
  817.         totalAlloc += 1;                                    // Round up to page boundary
  818.         
  819.         // Use PoolAllocate to get a page table - don't use the stack.
  820.         
  821.         p = MemAllocatePhysicallyContiguous (totalAlloc * pageSize, false);
  822.         
  823.         if (!p)
  824.         {
  825.             status = memFullErr;
  826.             sprintf (debugStr, "Asynch buf/PCL alloc failure, asked for %ld",
  827.                      (long) totalAlloc * pageSize);
  828.             FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  829.         }
  830.         
  831.         if (status == noErr)
  832.         {
  833.             // I think MemAllocatePhysicallyContiguous gives us memory starting
  834.             // on a page boundary.  But just in case, align ourselves:
  835.             
  836.             sprintf (debugStr, "Allocated phys memory at %08lx", (long) p);
  837. //            FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  838.  
  839.             p = (Ptr) ((((UInt32) p) + (pageSize - 1)) & ~(pageSize - 1));        // page-align
  840.  
  841.             sprintf (debugStr, "              Aligned to %08lx", (long) p);
  842. //            FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  843.  
  844.             // Mark this memory for Input, and learn the physical address    
  845.             ioPrep = &pPeleFWIMData->ioPrep;
  846.             ioPrep->options = kIOLogicalRanges | kIOIsInput | kIOIsOutput;
  847.             ioPrep->addressSpace = kCurrentAddressSpaceID;        // default
  848.             ioPrep->granularity = 0;                            // do it all now
  849.             ioPrep->firstPrepared = 0;
  850.             ioPrep->mappingEntryCount = totalAlloc;                // # of pages we will use
  851.             ioPrep->logicalMapping = 0;
  852.             ioPrep->physicalMapping = pPeleFWIMData->physAddrs;    // return list of phys addrs
  853.             ioPrep->rangeInfo.range.base = (void *) p;
  854.             ioPrep->rangeInfo.range.length = totalAlloc * pageSize;
  855.             
  856.             // There is no CheckpointIO which matches this.  The buffers are ours for keeps.
  857.             status = PrepareMemoryForIO (ioPrep);
  858.             if (status != noErr)
  859.             {
  860.                 sprintf (debugStr, "PrepMemIO status %ld    logical %08lx physical %08lx len %lx",
  861.                          (long) status,
  862.                          (long) ioPrep->rangeInfo.range.base,
  863.                          (long) pPeleFWIMData->physAddrs[0],
  864.                          (long) ioPrep->rangeInfo.range.length);
  865. //                FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  866.             }
  867.         }
  868.  
  869.         // Carve up what we got and store away the addrs
  870.         if (status == noErr)
  871.         {
  872.             // Asynch rcv buffers (kAsykcBufs)
  873.             
  874.             bufsDone = 0;
  875.             for (doBuf = 0; doBuf < bufPages; doBuf++)
  876.             {
  877.                 logPage = p + (doBuf * pageSize);
  878.                 physPage = (Ptr) pPeleFWIMData->physAddrs[doBuf];
  879.                 
  880.                 for (doPage = 0; doPage < bufsPerPage; doPage++)
  881.                 {
  882.                     if (bufsDone < kAsynchRxBufs)
  883.                     {
  884.                         offset = doPage * kAsyncRxPacketBufferSize;
  885.                         pPeleFWIMData->asynchBuf[bufsDone] = logPage + offset;
  886.                         pPeleFWIMData->asynchBufPhys[bufsDone] = physPage + offset;
  887.                     
  888.                         bufsDone++;
  889.                     }
  890.                 }
  891.             }
  892.             sprintf (debugStr, "Asynch bufs ready, log base %08lx, phys base %08lx, count %lx",
  893.                      (long) pPeleFWIMData->asynchBuf,
  894.                      (long) pPeleFWIMData->asynchBufPhys,
  895.                      (long) kAsynchRxBufs);
  896. //            FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  897.             
  898.             // Asynch xmit buffer (1)
  899.             
  900.             p += (bufPages * pageSize);
  901.             pPeleFWIMData->asynchXmitBuf = p;
  902.             pPeleFWIMData->asynchXmitBufPhys = pPeleFWIMData->physAddrs[bufPages];
  903.             
  904.             // Asynch rcv DMAs (kAsykcBufs)
  905.             // WARNING rcv code assumes all DMAs are contiguous.
  906.             // If made non-contig, will have to change several places
  907.             
  908.             p += pageSize;
  909.             pPeleFWIMData->asynchDMA = (PeleDMA *) p;
  910.             pPeleFWIMData->asynchDMAPhys = pPeleFWIMData->physAddrs[bufPages + 1];
  911.             
  912.             // Asynch xmit dbdma (16)  //zzz sloppy but should be OK
  913.  
  914.             p += (dmaPages * pageSize);
  915.             pPeleFWIMData->asynchXmitDMA = (PeleDMA *) p;
  916.             pPeleFWIMData->asynchXmitDMAPhys = pPeleFWIMData->physAddrs[bufPages + 1 + dmaPages];
  917.         }
  918.     }
  919.  
  920.     // Allocate asynch receive PCL data records.
  921.     if (status == noErr)
  922.     {
  923.         p = PoolAllocateResident (sizeof (PeleAsynchRxDMAData) * kAsynchRxBufs, true);
  924.         
  925.         if (p)
  926.             pPeleFWIMData->asynchRxDMADataList = (PeleAsynchRxDMADataPtr) p;
  927.         else
  928.             status = memFullErr;
  929.     }
  930.  
  931.     // Allocate asynch transmit data records.
  932.     // This is actually too many
  933.     if (status == noErr)
  934.     {
  935.         p = PoolAllocateResident (sizeof (PeleAsynchTxDMAData) * kNumAsynchTxDMAs, true);
  936.         
  937.         if (p)
  938.             pPeleFWIMData->AsynchTxDMADataList = (PeleAsynchTxDMADataPtr) p;
  939.         else
  940.             status = memFullErr;
  941.     }
  942.  
  943.     // Set up asynch transmit PCLs.
  944.     if (status == noErr)
  945.     {
  946.         PeleFWIMCreateAsynchTxDoneDMASegment (pPeleFWIMData);
  947.         PeleFWIMCreateAsynchTxDataDMA (pPeleFWIMData);
  948.     }
  949.  
  950.     // Create deferred task for handling bus resets.
  951.     if (status == noErr)
  952.     {
  953.         status = FWCreateDeferredTask (&(pPeleFWIMData->busResetDeferredTaskID),
  954.                                        PeleFWIMResetDeferredTask,
  955.                                        pPeleFWIMData);
  956.     }
  957.  
  958.     // Create deferred task for handling received asynch packets.
  959.     if (status == noErr)
  960.     {
  961.         status = FWCreateDeferredTask (&(pPeleFWIMData->asynchReceiveDeferredTaskID),
  962.                                        PeleFWIMDMAARDeferredTask,
  963.                                        pPeleFWIMData);
  964.     }
  965.  
  966.     // Create deferred task for handling received isoch packets.
  967.     if (status == noErr)
  968.     {
  969.         status = FWCreateDeferredTask (&(pPeleFWIMData->isochReceiveDeferredTaskID),
  970.                                        PeleFWIMDMAIsochReceiveDeferredTask,
  971.                                        pPeleFWIMData);
  972.     }
  973.  
  974.     // Create deferred task for handling transmitted isoch packets.
  975.     if (status == noErr)
  976.     {
  977.         status = FWCreateDeferredTask (&(pPeleFWIMData->isochTransmitDeferredTaskID),
  978.                                        PeleFWIMDMAIsochTransmitDeferredTask,
  979.                                        pPeleFWIMData);
  980.     }
  981.  
  982.     // Create deferred task for handling miscellaneous interrupts.
  983.     if (status == noErr)
  984.     {
  985.         status = FWCreateDeferredTask (&(pPeleFWIMData->miscInterruptDeferredTaskID),
  986.                                        PeleFWIMMiscInterruptDeferredTask,
  987.                                        pPeleFWIMData);
  988.     }
  989.  
  990.     // Install interrupt handler.
  991.     if (status == noErr)
  992.     {
  993.         status = PeleFWIMInstallInterruptHandler (pPeleFWIMData);
  994.     }
  995.  
  996.     // Use config space to enable bus mastering and memory space.
  997.     if (status == noErr)
  998.     {
  999.         status = ExpMgrConfigWriteWord (
  1000.                     pFWIMRegEntryID, (LogicalAddress) cwCommand,
  1001.                     (cwCommandEnableBusMaster | cwCommandEnableMemorySpace));
  1002.     }
  1003.  
  1004. //    FWDebugStr ((ConstStr255Param) "\p PeleFWIMInitialize: Start poking registers");
  1005.  
  1006.     if (status == noErr) status = PeleFWIMFullReset (pPeleFWIMData);
  1007.     
  1008. //    FWDebugStr ((ConstStr255Param) "\pPeleFWIMInitialize: Done!");
  1009.  
  1010.     return status;
  1011. }
  1012.  
  1013.  
  1014. ////////////////////////////////////////////////////////////////////////////////
  1015. //
  1016. // PeleFWIMFinalize
  1017. //
  1018. //   This is the FWIM finalizing proc.  It deallocates everything.
  1019. //   I believe this isn't actually used (yet).
  1020. //
  1021.  
  1022. static OSStatus    PeleFWIMFinalize(
  1023.     FWIMFinalizeParamsPtr        pFWIMFinalizeParams)
  1024. {
  1025.     PeleFWIMDataPtr                pPeleFWIMData;
  1026.     OSStatus                    status = noErr;
  1027.  
  1028.     // Get our internal data.
  1029.     pPeleFWIMData = (PeleFWIMDataPtr) pFWIMFinalizeParams->fwimSpecificData;
  1030.  
  1031.     //zzz deallocate everything.
  1032.  
  1033.     return status;
  1034. }
  1035.  
  1036.  
  1037. ////////////////////////////////////////////////////////////////////////////////
  1038. //
  1039. // PeleFWIMPollInterrupts
  1040. //
  1041. //   This proc checks for pending interrupts.
  1042. //   I believe this isn't actually used (yet), but it might apply if we needed
  1043. //   to process interrupts while they were disabled (say, if Pele was part of
  1044. //   the connection to our backing store).
  1045. //
  1046.  
  1047. static OSStatus    PeleFWIMPollInterrupts(
  1048.     FWIMPollInterruptsParamsPtr    pFWIMPollInterruptsParams)
  1049. {
  1050.     OSStatus                    status = noErr;
  1051.  
  1052.     status = PeleFWIMDispatchInterrupts
  1053.                 ((PeleFWIMDataPtr) pFWIMPollInterruptsParams->fwimSpecificData);
  1054.  
  1055.     return status;
  1056. }
  1057.  
  1058.  
  1059. ////////////////////////////////////////////////////////////////////////////////
  1060. //
  1061. // PeleFWIMGetRegisterBaseAddress
  1062. //
  1063. //   This proc uses the name registry to find the base address of the registers.
  1064. //
  1065.  
  1066. static OSStatus    PeleFWIMGetRegisterBaseAddress(
  1067.     PeleFWIMDataPtr                pPeleFWIMData)
  1068. {
  1069.     RegEntryIDPtr                pFWIMRegEntryID = &(pPeleFWIMData->FWIMRegEntryID);
  1070.     PCIAssignedAddressPtr        tempFWIMAddressesStorage = nil,
  1071.                                 pFWIMAddresses;
  1072.     Ptr                            pFWIMAddressesEnd;
  1073.     DeviceLogicalAddressPtr        tempFWIMLogicalAddressesStorage = nil,
  1074.                                 pFWIMLogicalAddresses;
  1075.     RegPropertyValueSize        propSize;
  1076.     UInt32                        assignedAddressesSize;
  1077.     Boolean                        done;
  1078.     OSStatus                    status = noErr;
  1079.  
  1080. //    FWDebugStr ((ConstStr255Param) "\pPeleFWIMGetRegisterBaseAddress");
  1081.  
  1082.     // Get assigned addresses property.
  1083.     status = RegistryPropertyGetSize
  1084.                 (pFWIMRegEntryID,
  1085.                  (RegPropertyNamePtr) kPCIAssignedAddressProperty,
  1086.                  &propSize);
  1087.  
  1088.     if (status == noErr)
  1089.     {
  1090.         tempFWIMAddressesStorage =
  1091.             (PCIAssignedAddressPtr) PoolAllocateResident (propSize, false);
  1092.         if (tempFWIMAddressesStorage == nil)
  1093.             status = memFullErr;
  1094.         else
  1095.             pFWIMAddresses = tempFWIMAddressesStorage;
  1096.     }
  1097.  
  1098.     if (status == noErr)
  1099.     {
  1100.         status = RegistryPropertyGet
  1101.                     (pFWIMRegEntryID,
  1102.                      (RegPropertyNamePtr) kPCIAssignedAddressProperty,
  1103.                      pFWIMAddresses,
  1104.                      &propSize);
  1105.         assignedAddressesSize = propSize;
  1106.     }
  1107.  
  1108.     // Get logical addresses property.
  1109.     if (status == noErr)
  1110.     {
  1111.         status = RegistryPropertyGetSize
  1112.                     (pFWIMRegEntryID,
  1113.                      (RegPropertyNamePtr) kAAPLDeviceLogicalAddress,
  1114.                      &propSize);
  1115.     }
  1116.  
  1117.     if (status == noErr)
  1118.     {
  1119.         tempFWIMLogicalAddressesStorage =
  1120.             (DeviceLogicalAddressPtr) PoolAllocateResident (propSize, false);
  1121.         if (tempFWIMLogicalAddressesStorage == nil)
  1122.             status = memFullErr;
  1123.         else
  1124.             pFWIMLogicalAddresses = tempFWIMLogicalAddressesStorage;
  1125.     }
  1126.  
  1127.     if (status == noErr)
  1128.     {
  1129.         status = RegistryPropertyGet
  1130.                     (pFWIMRegEntryID,
  1131.                      (RegPropertyNamePtr) kAAPLDeviceLogicalAddress,
  1132.                      pFWIMLogicalAddresses,
  1133.                      &propSize);
  1134.     }
  1135.  
  1136.     // Scan addresses until we find the one at config space 0x10.
  1137.     if (status == noErr)
  1138.     {
  1139.         pFWIMAddressesEnd = ((Ptr) pFWIMAddresses) + assignedAddressesSize;
  1140.         done = false;
  1141.  
  1142.         while ((((Ptr) pFWIMAddresses) < pFWIMAddressesEnd) && (!done))
  1143.         {
  1144.             if (pFWIMAddresses->registerNumber == 0x10)
  1145.             {
  1146.                 // There is a certain prototype system in which Open Firmware
  1147.                 // doesn't seem to work quite right yet.  If we find that the
  1148.                 // base register is zero, substitute another value for now.
  1149.                 
  1150.                 if (!*pFWIMLogicalAddresses)
  1151.                 {
  1152.                     pPeleFWIMData->pPeleRegisters = (PeleRegistersPtr) pFWIMAddresses->address.lo;
  1153.                     
  1154.                     sprintf (debugStr, "Base register 0, using %08lx", (long) pFWIMAddresses->address.lo);
  1155.                     FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  1156.                 }
  1157.                 else
  1158.                 {
  1159.                     pPeleFWIMData->pPeleRegisters = (PeleRegistersPtr) *pFWIMLogicalAddresses;
  1160.                 }
  1161.                 done = true;
  1162.             }
  1163.  
  1164.             pFWIMAddresses++;
  1165.             pFWIMLogicalAddresses++;
  1166.         }
  1167.  
  1168.         if (!done)
  1169.             status = paramErr;
  1170.     }
  1171.  
  1172.     // Deallocate temp storage.
  1173.     if (tempFWIMAddressesStorage != nil)
  1174.         PoolDeallocate ((LogicalAddress) tempFWIMAddressesStorage);
  1175.  
  1176.     if (tempFWIMLogicalAddressesStorage != nil)
  1177.         PoolDeallocate ((LogicalAddress) tempFWIMLogicalAddressesStorage);
  1178.  
  1179.     return status;
  1180. }
  1181.  
  1182.  
  1183. ////////////////////////////////////////////////////////////////////////////////
  1184. //
  1185. // PeleFWIMInstallInterruptHandler
  1186. //
  1187. //   This proc installs the chip interrupt handler.
  1188. //
  1189.  
  1190. static OSStatus    PeleFWIMInstallInterruptHandler(
  1191.     PeleFWIMDataPtr                pPeleFWIMData)
  1192. {
  1193.     RegEntryIDPtr                pFWIMRegEntryID = &(pPeleFWIMData->FWIMRegEntryID);
  1194.     ISTProperty                    interruptSets;
  1195.     InterruptSetID                interruptSetID;
  1196.     InterruptMemberNumber        interruptMemberNumber;
  1197.     void                        *oldInterruptRefCon;
  1198.     InterruptHandler            oldInterruptHandler;
  1199.     InterruptEnabler            interruptEnabler;
  1200.     InterruptDisabler            interruptDisabler;
  1201.     RegPropertyValueSize        propSize;
  1202.     OSStatus                    status = noErr;
  1203.  
  1204. //    FWDebugStr ((ConstStr255Param) "\pPeleFWIMInstallInterruptHandler");
  1205.  
  1206.     // Get our interrupt set from the name registry.
  1207.     propSize = sizeof (ISTProperty);
  1208.     status = RegistryPropertyGet (pFWIMRegEntryID, kISTPropertyName,
  1209.                                   &interruptSets, &propSize);
  1210.     interruptSetID = interruptSets[kISTChipInterruptSource].setID;
  1211.     interruptMemberNumber = interruptSets[kISTChipInterruptSource].member;
  1212.  
  1213.     // Get the interrupt enabler and disabler for our chip interrupt set.
  1214.     if (status == noErr)
  1215.     {
  1216.         status = GetInterruptFunctions
  1217.                     (interruptSetID, interruptMemberNumber,
  1218.                      &oldInterruptRefCon, &oldInterruptHandler,
  1219.                      &interruptEnabler, &interruptDisabler);
  1220.     }
  1221.  
  1222.     // Install the refCon and interrupt handler for our chip interrupt set.
  1223.     if (status == noErr)
  1224.     {
  1225.         status = InstallInterruptFunctions
  1226.                     (interruptSetID, interruptMemberNumber,
  1227.                      pPeleFWIMData, (InterruptHandler) PeleFWIMInterruptHandler,
  1228.                      nil, nil);
  1229.     }
  1230.  
  1231.     // Add info to our FWIM Data record.
  1232.     if (status == noErr)
  1233.     {
  1234.         pPeleFWIMData->interruptSetMember.setID = interruptSetID;
  1235.         pPeleFWIMData->interruptSetMember.member = interruptMemberNumber;
  1236.         pPeleFWIMData->oldInterruptRefCon = oldInterruptRefCon;
  1237.         pPeleFWIMData->oldInterruptHandler = oldInterruptHandler;
  1238.         pPeleFWIMData->interruptEnabler = interruptEnabler;
  1239.         pPeleFWIMData->interruptDisabler = interruptDisabler;
  1240.     }
  1241.  
  1242.     return status;
  1243. }
  1244.  
  1245.  
  1246. ////////////////////////////////////////////////////////////////////////////////
  1247. //
  1248. // PeleFWIMcrc16
  1249. //
  1250. // Compute the CRC-16 value of a block of quadlets.
  1251. // Adapted from Table 23 of IEEE 1212.
  1252. // Takes quadlet pointer and count of quadlets
  1253.  
  1254. static UInt16 PeleFWIMcrc16(
  1255.     UInt32                        *data,
  1256.     UInt32                        count)
  1257. {
  1258.     SInt32                        shift;
  1259.     UInt16                        sum, next = 0;
  1260.     UInt32                        doCount = count, *doData = data;
  1261.     
  1262.     while (doCount--)
  1263.     {
  1264.         for (shift = 28; shift >= 0; shift -= 4)        // 8 times, 4 bits each time
  1265.         {
  1266.             sum = ((next >> 12) ^ (*doData >> shift)) & 0x0f;        // get 4 bits
  1267.             next = (next << 4) ^ (sum << 12) ^ (sum << 5) ^ sum;    // apply them
  1268.         }
  1269.         doData++;
  1270.     }
  1271.     
  1272.     return next;
  1273. }
  1274.  
  1275.  
  1276. ////////////////////////////////////////////////////////////////////////////////
  1277. //
  1278. // PeleFWIMFullReset
  1279. //
  1280.  
  1281. static OSStatus    PeleFWIMFullReset(
  1282.     PeleFWIMDataPtr                pPeleFWIMData)
  1283. {
  1284.     PeleRegistersPtr            pPeleRegs;
  1285.     UInt32                        interruptMask;
  1286.     OSStatus                    status = noErr;
  1287.  
  1288. //    FWDebugStr ((ConstStr255Param) "\p(Pele) PeleFWIMFullReset");
  1289.  
  1290.     pPeleRegs = pPeleFWIMData->pPeleRegisters;
  1291.     
  1292.     // Reset everything possible
  1293.     pPeleRegs->reset =
  1294.         EndianSwapImm32Bit (kPeleResetReceiver |
  1295.                             kPeleResetTransmitter |
  1296.                             kPeleResetRF |
  1297.                             kPeleResetITF |
  1298.                             kPeleResetATF);
  1299.     SynchronizeIO ();
  1300.     
  1301.     // Note, some older Pele parts don't have the LinkOnEnable bit.
  1302.     // Setting it should be harmless (and useless) on those parts.
  1303.     
  1304.     // Clear resets and turn on link
  1305.     pPeleRegs->reset = EndianSwapImm32Bit (kPeleResetLinkOnEnable);
  1306.     SynchronizeIO ();
  1307.  
  1308.     // Create the asynch receive program.
  1309.     PeleFWIMCreateAsynchRxDMAProgram (pPeleFWIMData);
  1310.  
  1311.     // Start asynch receive program.
  1312.     PeleFWIMStartAsynchRxDMAProgram
  1313.         (pPeleFWIMData, &(pPeleFWIMData->asynchRxDMADataList[kAsynchRxFirstPacketDMA]));
  1314.  
  1315.     // Could set hardware retry counter here (?)
  1316.     
  1317.     // Enable Receiver and Transmitter, disable physical DMA
  1318.     pPeleRegs->control =
  1319.         EndianSwapImm32Bit ((kPelePhysDMAnoAccess << kPeleControlPhysDMAEnablePhase) |
  1320.                             kPeleControlReceiveEnable |
  1321.                             kPeleControlTransmitEnable);
  1322.     SynchronizeIO ();
  1323.     pPeleRegs->packetControl = EndianSwapImm32Bit (kPelePacketControlRcvSelfID);
  1324.     SynchronizeIO ();
  1325.     
  1326.     // Set our bus number to default 0x3FF.
  1327.     //zzz If 1394.1 is ever finished, we'll need to know how to learn the real number
  1328.     // Pele's node number register is read-only, so we can just OR in the 0x3FF:
  1329.     pPeleRegs->nodeID |= EndianSwapImm32Bit (0x3FF << kPeleNodeIDBusNumberPhase);
  1330.     SynchronizeIO ();
  1331.     
  1332. //    FWDebugStr ((ConstStr255Param) "\pPeleFWIMFullReset: Enable interrupts");
  1333.  
  1334.     // Enable chip interrupts.
  1335.     if (status == noErr)
  1336.     {
  1337.         (*(pPeleFWIMData->interruptEnabler)) (pPeleFWIMData->interruptSetMember,
  1338.                                             pPeleFWIMData->oldInterruptRefCon);
  1339.     }
  1340.  
  1341.     // Enable interrupts for bus resets, phy registers, and DMA ints
  1342.     {
  1343.         interruptMask = kPeleIntBusReset |
  1344.                         kPeleIntDMAAR |
  1345.                         kPeleIntDMAIRA |
  1346.                         kPeleIntDMAIRB |
  1347.                         kPeleIntDMAITA;
  1348.  
  1349. #ifndef PELE_NO_PHY_REG_RCVD
  1350.         interruptMask |= kPeleIntPhyRegRcvd;
  1351. #endif
  1352.  
  1353.         pPeleRegs->interruptMask = EndianSwap32Bit (interruptMask);
  1354.         SynchronizeIO ();
  1355.  
  1356.         // Enable additional interrupts only if we are running FireBug.
  1357.         // Interrupts will be reported to FireBug.
  1358.         // Normally there's nothing we can do about these interrupts.
  1359.         
  1360. #ifdef PeleFireBug
  1361.         pPeleRegs->interruptMask |=
  1362.             EndianSwapImm32Bit (kPeleIntHdrErr);
  1363.         SynchronizeIO ();                
  1364. #endif
  1365.  
  1366.     }
  1367.     
  1368.     // Enable Cycle Timer.
  1369.     pPeleRegs->control |= EndianSwapImm32Bit (kPeleControlCycleTimerEnable);
  1370.     SynchronizeIO ();
  1371.  
  1372. //    FWDebugStr ((ConstStr255Param) "\pPeleFWIMFullReset: Survived!");
  1373.  
  1374.     return noErr;        // at no point did we check any status
  1375. }
  1376.  
  1377.  
  1378. ////////////////////////////////////////////////////////////////////////////////
  1379. //
  1380. // PeleFWIMExceptionHandler
  1381. //
  1382. //   This proc handles exceptions.
  1383. //   I believe that this never happens (yet).
  1384. //
  1385.  
  1386. static OSStatus    PeleFWIMExceptionHandler(
  1387.     ExceptionInformationPowerPC    *theException)
  1388. {
  1389.     OSStatus                    status = noErr;
  1390.  
  1391.     FWDebugStr ((ConstStr255Param) "\pPeleFWIMExceptionHandler");
  1392.  
  1393.     return status;
  1394. }
  1395.  
  1396.  
  1397. ////////////////////////////////////////////////////////////////////////////////
  1398. //
  1399. // PeleFWIMInterruptHandler
  1400. //
  1401. //   This is the handler proc for chip interrupts.
  1402. //
  1403.  
  1404. static InterruptMemberNumber    PeleFWIMInterruptHandler(
  1405.     InterruptSetMember            interruptSetMember,
  1406.     void                        *interruptRefCon,
  1407.     UInt32                        interruptCount)
  1408. {
  1409.     PeleFWIMDispatchInterrupts ((PeleFWIMDataPtr) interruptRefCon);
  1410.  
  1411.     return kIsrIsComplete;
  1412. }
  1413.  
  1414.  
  1415. ////////////////////////////////////////////////////////////////////////////////
  1416. //
  1417. // PeleFWIMDispatchInterrupts
  1418. //
  1419. //   This proc dispatches any pending interrupts.
  1420. //
  1421.  
  1422. static OSStatus    PeleFWIMDispatchInterrupts(
  1423.     PeleFWIMDataPtr                pPeleFWIMData)
  1424. {
  1425.     PeleRegistersPtr            pPeleRegs;
  1426.     UInt32                        interruptEvents, interruptEventsLittleEndian;
  1427.     OSStatus                    status = noErr;
  1428.  
  1429.     // Get our register base address.
  1430.     pPeleRegs = pPeleFWIMData->pPeleRegisters;
  1431.  
  1432.     // Read PCI interrupt status register.
  1433.     interruptEventsLittleEndian = pPeleRegs->interruptEvents;
  1434.     interruptEvents = EndianSwap32Bit (interruptEventsLittleEndian);
  1435.  
  1436.     // Note - there are lots of kinds of ints other than 1394 and DMA
  1437.     // that can happen.  We'll probably want to catch some of them.
  1438.  
  1439.     // Check for bus reset, must do that first
  1440.     if (interruptEvents & kPeleIntBusReset)
  1441.         PeleFWIMHandleResetInterrupt (pPeleFWIMData);
  1442.  
  1443. #ifndef PELE_NO_PHY_REG_RCVD
  1444.     // Check for PHY register received
  1445.     if (interruptEvents & kPeleIntPhyRegRcvd)
  1446.         PeleFWIMHandlePhyRegRcvdInterrupt (pPeleFWIMData);
  1447. #endif
  1448.  
  1449.     // Check for DMA interrupts:
  1450.  
  1451.     if (interruptEvents & kPeleIntDMAAR)
  1452.         PeleFWIMHandleDMAARInterrupt (pPeleFWIMData);
  1453.  
  1454.     if (interruptEvents & kPeleIntDMAIRA)
  1455.         PeleFWIMHandleDMAIRAInterrupt (pPeleFWIMData);
  1456.     
  1457.     // Same handler as IRA:
  1458.     if (interruptEvents & kPeleIntDMAIRB)
  1459.         PeleFWIMHandleDMAIRAInterrupt (pPeleFWIMData);
  1460.  
  1461.     if (interruptEvents & kPeleIntDMAITA)
  1462.         PeleFWIMHandleDMAITAInterrupt (pPeleFWIMData);
  1463.  
  1464. #ifdef PeleFireBug
  1465.         if (!(interrupt & kPelePHY_BUSRESET))
  1466.         {
  1467.             //PeleFWIMHandleMiscInterrupt (pPeleFWIMData);
  1468.         }
  1469. #endif
  1470.  
  1471.     // Clear the interrupts.
  1472.     pPeleRegs->interruptClear = interruptEventsLittleEndian;
  1473.     SynchronizeIO ();
  1474.  
  1475.     return status;
  1476. }
  1477.  
  1478.  
  1479. ////////////////////////////////////////////////////////////////////////////////
  1480. //
  1481. // PeleFWIMHandleDMAARInterrupt
  1482. //
  1483. //   This proc handles asynch receive DMA interrupts.
  1484. //
  1485.  
  1486. static void PeleFWIMHandleDMAARInterrupt(
  1487.     PeleFWIMDataPtr                pPeleFWIMData)
  1488. {    
  1489.     OSStatus                    status = noErr;
  1490.  
  1491.     if (!(pPeleFWIMData->asynchReceiveDTScheduled))
  1492.     {
  1493.         status = FWScheduleDeferredTask (pPeleFWIMData->asynchReceiveDeferredTaskID, nil);
  1494.  
  1495.         if (status == noErr)
  1496.             pPeleFWIMData->asynchReceiveDTScheduled = true;
  1497.     }
  1498. }
  1499.  
  1500.  
  1501. ////////////////////////////////////////////////////////////////////////////////
  1502. //
  1503. // PeleFWIMHandleDMAIRAInterrupt
  1504. //
  1505. //   This proc handles isoch receive A DMA interrupts.
  1506. //
  1507.  
  1508. static void PeleFWIMHandleDMAIRAInterrupt(
  1509.     PeleFWIMDataPtr                pPeleFWIMData)
  1510. {
  1511.     OSStatus                    status = noErr;
  1512.  
  1513.     if (!(pPeleFWIMData->isochReceiveDTScheduled))
  1514.     {
  1515.         status = FWScheduleDeferredTask (pPeleFWIMData->isochReceiveDeferredTaskID, nil);
  1516.  
  1517.         if (status == noErr)
  1518.             pPeleFWIMData->isochReceiveDTScheduled = true;
  1519.     }
  1520. }
  1521.  
  1522.  
  1523. ////////////////////////////////////////////////////////////////////////////////
  1524. //
  1525. // PeleFWIMHandleDMAITAInterrupt
  1526. //
  1527. //   This proc handles isoch transmit A DMA interrupts.
  1528. //
  1529.  
  1530. static void PeleFWIMHandleDMAITAInterrupt(
  1531.     PeleFWIMDataPtr                pPeleFWIMData)
  1532. {
  1533.     OSStatus                    status = noErr;
  1534.  
  1535.     if (!(pPeleFWIMData->isochTransmitDTScheduled))
  1536.     {
  1537.         status = FWScheduleDeferredTask (pPeleFWIMData->isochTransmitDeferredTaskID, nil);
  1538.  
  1539.         if (status == noErr)
  1540.             pPeleFWIMData->isochTransmitDTScheduled = true;
  1541.     }
  1542. }
  1543.  
  1544.  
  1545. ////////////////////////////////////////////////////////////////////////////////
  1546. //
  1547. // PeleFWIMHandleResetInterrupt
  1548. //
  1549. //   This proc handles bus reset interrupts.
  1550. //zzz must be able to handle two resets happening before we process one.
  1551. //
  1552.  
  1553. static void PeleFWIMHandleResetInterrupt(
  1554.     PeleFWIMDataPtr                pPeleFWIMData)
  1555. {
  1556.     PeleRegistersPtr            pPeleRegs = pPeleFWIMData->pPeleRegisters;
  1557.     UInt32                        control;
  1558.     OSStatus                    status = noErr;
  1559.     
  1560.     // Pele disables the asynch transmitter on bus resets.  But, that disables
  1561.     // the sending of cycle-start packets if Pele is root.  So, turn it back on.
  1562.     // Before we do that, ensure that the asynch transmit DMA is stopped.
  1563.     
  1564.     pPeleRegs->asynchTransmit.channelControl = EndianSwapImm32Bit (kPeleClrAll);
  1565.     SynchronizeIO();
  1566.     
  1567.     pPeleFWIMData->asynchTxDoneFlag = 0xFFFFFFFF;
  1568.  
  1569.     // I think there may be a hadrware bug in (some) Peles that will cause the
  1570.     // cycle master function to jam if it had already tried to send a cycle start
  1571.     // but found the transmitter disabled.  To try to avoid this, first turn off
  1572.     // the cycle master, then enable the transmitter, then turn the cycle master
  1573.     // back on (only if it was already on).  Soon after this, we'll get phy reg
  1574.     // 0 to tell us if we're still root or not - but for now, we don't know yet.
  1575.     
  1576.     control = pPeleRegs->control | EndianSwapImm32Bit (kPeleControlTransmitEnable);
  1577.     SynchronizeIO ();
  1578.     pPeleRegs->control &= ~EndianSwapImm32Bit (kPeleControlCycleMaster);
  1579.     SynchronizeIO ();
  1580.     pPeleRegs->control = control;
  1581.     SynchronizeIO ();
  1582.     
  1583.     // Invalidate bus generation number.
  1584.     pPeleFWIMData->generationValid = false;
  1585.  
  1586.     // Process the reset.
  1587.     status = FWProcessBusReset (pPeleFWIMData->fwimID);
  1588.  
  1589.     // Schedule deferred task to handle reset.
  1590.     if (!(pPeleFWIMData->busResetDTScheduled))
  1591.     {
  1592.         status = FWScheduleDeferredTask (pPeleFWIMData->busResetDeferredTaskID, nil);
  1593.  
  1594.         if (status == noErr)
  1595.             pPeleFWIMData->busResetDTScheduled = true;
  1596.     }
  1597.     
  1598. #ifdef PELE_NO_PHY_REG_RCVD
  1599.     // We're never going to get a PHY register received interrupt, so take care of this now:
  1600.     {
  1601.         AbsoluteTime                absoluteDuration;
  1602.         
  1603.         // This should be enough time for the PHY to send register 0 to us.
  1604.         
  1605.         absoluteDuration = DurationToAbsolute (200 * durationMicrosecond);
  1606.         DelayForHardware (absoluteDuration);
  1607.  
  1608.         // It might be possible to poll for kPeleNodeIDValid rathen than delay 200 microseconds.
  1609.         // If that works, it is probably a better solution.
  1610.         
  1611.         if ((pPeleRegs->nodeID & kPeleNodeIDValid) && !(pPeleRegs->nodeID & kPeleNodeIDRoot))
  1612.         {
  1613.             if (pPeleRegs->control & EndianSwapImm32Bit (kPeleControlCycleMaster))
  1614.             {
  1615.                 // See comments in PeleFWIMHandlePhyRegRcvdInterrupt.
  1616.                 
  1617.                 // Disable cycle mastering.
  1618.                 pPeleRegs->control &= ~EndianSwapImm32Bit (kPeleControlCycleMaster);
  1619.                 SynchronizeIO ();
  1620.             }
  1621.         }
  1622.     }
  1623. #endif
  1624. }
  1625.  
  1626.  
  1627. ////////////////////////////////////////////////////////////////////////////////
  1628. //
  1629. // PeleFWIMHandlePhyRegRcvdInterrupt
  1630. //
  1631. //   This proc handles phy register receive interrupts.
  1632. //   Any time we get register 0, keep a copy.
  1633. //   Also keep a copy of the most recently received register.
  1634. //
  1635. //   Some Pele-derived designs do not support this interrupt.
  1636. //
  1637.  
  1638. #ifndef PELE_NO_PHY_REG_RCVD
  1639. static void PeleFWIMHandlePhyRegRcvdInterrupt(
  1640.     PeleFWIMDataPtr                pPeleFWIMData)
  1641. {
  1642.     PeleRegistersPtr            pPeleRegs;
  1643.     OSStatus                    status = noErr;
  1644.     UInt32                        phyData;
  1645.  
  1646.     // This happens about 150 microseconds after a bus reset, when the PHY sends
  1647.     // register zero automatically.  This also happens after we do a PHY read
  1648.     // in PeleFWIMReadPHYRegister.
  1649.         
  1650.     pPeleRegs = pPeleFWIMData->pPeleRegisters;
  1651.  
  1652.     // NOTE This register read will clear the RdDone bit if it is set.
  1653.     
  1654.     pPeleFWIMData->lastPhyControl = pPeleRegs->phyControl;
  1655.     phyData = EndianSwap32Bit (pPeleFWIMData->lastPhyControl);    
  1656.     
  1657.     // If it was register 0 that came in, do some more work:
  1658.     
  1659.     if (((phyData & kPelePhyControlRdAddr) >> kPelePhyControlRdAddrPhase) == 0)
  1660.     {
  1661.         phyData = (phyData & kPelePhyControlRdData) >> kPelePhyControlRdDataPhase;
  1662.         pPeleFWIMData->lastPhyReg0 = phyData;
  1663.                 
  1664.         // If there was a bus reset, and we were cycle master, and we aren't any more,
  1665.         // we need to turn off the cycle master ASAP.  For one thing, we probably will
  1666.         // not receive cycle start packets as long as kPeleControlCycleMaster is set.
  1667.         // There may be other reasons to do this too (hardware bugs).
  1668.  
  1669.         if ((phyData & kPelePhyR) == 0)        // if not root
  1670.         {
  1671.             if (pPeleRegs->control & EndianSwapImm32Bit (kPeleControlCycleMaster))
  1672.             {
  1673.                 // zzz
  1674.                 // There are some possible race conditions here.
  1675.                 // We could still be turning on cycle master due to a previous config.
  1676.                 // One solution might be to (when we want to do that) cause a PHY read
  1677.                 // that will bring us here, then turn it on here.
  1678.                 
  1679.                 // Disable cycle mastering.
  1680.                 pPeleRegs->control &= ~EndianSwapImm32Bit (kPeleControlCycleMaster);
  1681.                 SynchronizeIO ();
  1682.             }
  1683.         }
  1684.     }
  1685. }
  1686. #endif
  1687.  
  1688.  
  1689. ////////////////////////////////////////////////////////////////////////////////
  1690. //
  1691. // PeleFWIMHandleMiscInterrupt
  1692. //
  1693. //   This proc handles miscellaneous interrupts.
  1694. //   This is only called #ifdef PeleFireBug
  1695. //  zzz no mechanism to prevent race condition in reporting.
  1696. //
  1697.  
  1698. static void PeleFWIMHandleMiscInterrupt(
  1699.     PeleFWIMDataPtr                pPeleFWIMData)
  1700. {
  1701.     OSStatus                    status = noErr;
  1702.  
  1703.     pPeleFWIMData->miscInterrupt = EndianSwap32Bit (
  1704.         pPeleFWIMData->pPeleRegisters->interruptEvents &
  1705.         pPeleFWIMData->pPeleRegisters->interruptMask);
  1706.  
  1707.     // Schedule deferred task.
  1708.     if ((pPeleFWIMData->miscInterrupt) && !(pPeleFWIMData->miscInterruptDTScheduled))
  1709.     {
  1710.         status = FWScheduleDeferredTask (pPeleFWIMData->miscInterruptDeferredTaskID, nil);
  1711.  
  1712.         if (status == noErr)
  1713.             pPeleFWIMData->miscInterruptDTScheduled = true;
  1714.     }
  1715. }
  1716.  
  1717.  
  1718. ////////////////////////////////////////////////////////////////////////////////
  1719. //
  1720. // PeleFWIMResetBus
  1721. //
  1722. //   This routine initiates a bus reset.
  1723. //
  1724.  
  1725. static OSStatus PeleFWIMResetBus(
  1726.     FWIMCommandParamsPtr        pFWIMCommandParams,
  1727.     UInt32                        *pCommandAcceptance)
  1728. {
  1729.     PeleFWIMDataPtr                pPeleFWIMData;
  1730.     PeleRegistersPtr            pPeleRegs;
  1731.     UInt32                        phyReg;
  1732.     OSStatus                    status = noErr;
  1733.  
  1734.     // Get our internal data.
  1735.     pPeleFWIMData = (PeleFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  1736.  
  1737. #ifdef PeleFireBug
  1738.     sprintf (fireBug, "PeleFWIM:  Bus reset from FSL");
  1739.     PeleFWIMFireBugMsg (pPeleFWIMData, fireBug);
  1740. #endif
  1741.  
  1742.     // Set pending command.
  1743.     pPeleFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMCommandParams;
  1744.     pPeleFWIMData->pendingFWIMCommandStatus = kPelePendingFWIMCommandBusy;
  1745.  
  1746.     // Get base address of Pele registers.
  1747.     pPeleRegs = pPeleFWIMData->pPeleRegisters;
  1748.  
  1749.     // Issue the reset.
  1750.     phyReg = PeleFWIMReadPhyRegister (pPeleFWIMData, pPeleRegs, kPelePhyIBRAddress);
  1751.     phyReg |= kPelePhyIBR;
  1752.     PeleFWIMWritePhyRegister (pPeleRegs, kPelePhyIBRAddress, phyReg);
  1753.  
  1754.     // Finish up command.
  1755.     pPeleFWIMData->pPendingFWIMCommand = nil;
  1756.     status = FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
  1757.  
  1758.     // Return command acceptance.
  1759.     //zzz what if we call FWIMCommandIsComplete before returning this???
  1760.     //zzz well, it still works, but will it always?
  1761.     //zzz actually, when we switch to the dispatch table, each routine can return
  1762.     //zzz the appropriate acceptance, so don't worry about it for now.
  1763.     *pCommandAcceptance = kFWIMCommandAcceptNoMore;
  1764.  
  1765.     return status;
  1766. }
  1767.  
  1768.  
  1769. ////////////////////////////////////////////////////////////////////////////////
  1770. //
  1771. // PeleFWIMSetContenderBit
  1772. //
  1773. //   This routine sets the contender bit in the self ID on the next bus reset.
  1774. //   zzz NYI - different boards do this in different ways
  1775.  
  1776. static OSStatus PeleFWIMSetContenderBit(
  1777.     FWIMCommandParamsPtr        pFWIMCommandParams,
  1778.     UInt32                        *pCommandAcceptance)
  1779. {
  1780.     PeleFWIMDataPtr                pPeleFWIMData;
  1781.     PeleRegistersPtr            pPeleRegs;
  1782.     OSStatus                    status = noErr;
  1783.  
  1784.     // Get our internal data and register base address.
  1785.     pPeleFWIMData = (PeleFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  1786.     pPeleRegs = pPeleFWIMData->pPeleRegisters;
  1787.  
  1788.     // Set pending command.
  1789.     pPeleFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMCommandParams;
  1790.     pPeleFWIMData->pendingFWIMCommandStatus = kPelePendingFWIMCommandBusy;
  1791.  
  1792.     // Program the contender bit to be set on next reset.
  1793.     SynchronizeIO ();
  1794.  
  1795.     // Finish up command.
  1796.     pPeleFWIMData->pPendingFWIMCommand = nil;
  1797.     status = FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
  1798.  
  1799.     // Return command acceptance.
  1800.     //zzz what if we call FWIMCommandIsComplete before returning this???
  1801.     //zzz well, it still works, but will it always?
  1802.     //zzz actually, when we switch to the dispatch table, each routine can return
  1803.     //zzz the appropriate acceptance, so don't worry about it for now.
  1804.     *pCommandAcceptance = kFWIMCommandAcceptNoMore;
  1805.  
  1806.     return status;
  1807. }
  1808.  
  1809.  
  1810. ////////////////////////////////////////////////////////////////////////////////
  1811. //
  1812. // PeleFWIMClearContenderBit
  1813. //
  1814. //   This routine clears the contender bit in the self ID on the next bus reset.
  1815. //   zzz see above
  1816.  
  1817. static OSStatus PeleFWIMClearContenderBit(
  1818.     FWIMCommandParamsPtr        pFWIMCommandParams,
  1819.     UInt32                        *pCommandAcceptance)
  1820. {
  1821.     PeleFWIMDataPtr                pPeleFWIMData;
  1822.     PeleRegistersPtr            pPeleRegs;
  1823.     OSStatus                    status = noErr;
  1824.  
  1825.     // Get our internal data and register base address.
  1826.     pPeleFWIMData = (PeleFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  1827.     pPeleRegs = pPeleFWIMData->pPeleRegisters;
  1828.  
  1829.     // Set pending command.
  1830.     pPeleFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMCommandParams;
  1831.     pPeleFWIMData->pendingFWIMCommandStatus = kPelePendingFWIMCommandBusy;
  1832.  
  1833.     // Program the contender bit to be clear on next reset.
  1834.     SynchronizeIO ();
  1835.  
  1836.     // Finish up command.
  1837.     pPeleFWIMData->pPendingFWIMCommand = nil;
  1838.     status = FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
  1839.  
  1840.     // Return command acceptance.
  1841.     //zzz what if we call FWIMCommandIsComplete before returning this???
  1842.     //zzz well, it still works, but will it always?
  1843.     //zzz actually, when we switch to the dispatch table, each routine can return
  1844.     //zzz the appropriate acceptance, so don't worry about it for now.
  1845.     *pCommandAcceptance = kFWIMCommandAcceptNoMore;
  1846.  
  1847.     return status;
  1848. }
  1849.  
  1850.  
  1851. ////////////////////////////////////////////////////////////////////////////////
  1852. //
  1853. // PeleFWIMEnableCycleMaster
  1854. //
  1855. //   This routine enables cycle mastering.
  1856. //   Unlike the disable routine below, which is somewhat redundant, this routine
  1857. //   is the only place we set cycle master.  Setting cycle master is done only
  1858. //   after the IRM assigns a new cycle master, which is rare and isn't supposed
  1859. //   to be particularly fast. (ie, cycle loss is OK)
  1860. //
  1861. //   zzz should there be a mechanism to report failure, such as FSL asked us to
  1862. //   become cyclemaster, but by the time we got here, we aren't root anymore?
  1863. //
  1864.  
  1865. static OSStatus PeleFWIMEnableCycleMaster(
  1866.     FWIMCommandParamsPtr        pFWIMCommandParams,
  1867.     UInt32                        *pCommandAcceptance)
  1868. {
  1869.     PeleFWIMDataPtr                pPeleFWIMData;
  1870.     PeleRegistersPtr            pPeleRegs;
  1871.     OSStatus                    status = noErr;
  1872.  
  1873.     // Get our internal data and register base address.
  1874.     pPeleFWIMData = (PeleFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  1875.     pPeleRegs = pPeleFWIMData->pPeleRegisters;
  1876.  
  1877.     // Set pending command.
  1878.     pPeleFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMCommandParams;
  1879.     pPeleFWIMData->pendingFWIMCommandStatus = kPelePendingFWIMCommandBusy;
  1880.  
  1881.     // Enable cycle mastering if we're root.
  1882.     // There is a race condition:  We could lose root before we turn on the cycle
  1883.     // master, and then turn it on.  In theory Pele won't send cycleStart if it is
  1884.     // not root, but it probably won't accept them if we leave the cycle master bit
  1885.     // turned on, so we'll still be messed up.  So, after turning it on, make sure
  1886.     // we're still root, and if not, turn it back off.  This is the only place it
  1887.     // can be turned on, so then we should be OK.
  1888.     
  1889.     if (pPeleFWIMData->root)
  1890.     {
  1891.         // For safety, triple-check that we're root:
  1892.         if ((((volatile UInt8) (pPeleFWIMData->lastPhyReg0)) & kPelePhyR) &&
  1893.             (pPeleRegs->nodeID & EndianSwapImm32Bit (kPeleNodeIDRoot)) &&
  1894.             (pPeleRegs->nodeID & EndianSwapImm32Bit (kPeleNodeIDValid)))
  1895.         {
  1896.             pPeleRegs->control |= EndianSwapImm32Bit (kPeleControlCycleMaster);
  1897.             SynchronizeIO ();
  1898.  
  1899.             // And now, if we lost root, we may have screwed up control.
  1900.             // This isn't perfect, but at least turn off the CYCMASTER
  1901.  
  1902.             if ((!(((volatile UInt8) (pPeleFWIMData->lastPhyReg0)) & kPelePhyR)) ||
  1903.                 !(pPeleRegs->nodeID & EndianSwapImm32Bit (kPeleNodeIDRoot)) ||
  1904.                 !(pPeleRegs->nodeID & EndianSwapImm32Bit (kPeleNodeIDValid)))
  1905.             {
  1906.                 pPeleRegs->control &= ~EndianSwapImm32Bit (kPeleControlCycleMaster);
  1907.                 SynchronizeIO ();
  1908.             }
  1909.         }
  1910.     }
  1911.  
  1912.  
  1913.     // Finish up command.
  1914.     pPeleFWIMData->pPendingFWIMCommand = nil;
  1915.     status = FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
  1916.  
  1917.     // Return command acceptance.
  1918.     //zzz what if we call FWIMCommandIsComplete before returning this???
  1919.     //zzz well, it still works, but will it always?
  1920.     //zzz actually, when we switch to the dispatch table, each routine can return
  1921.     //zzz the appropriate acceptance, so don't worry about it for now.
  1922.     *pCommandAcceptance = kFWIMCommandAcceptNoMore;
  1923.  
  1924.     return status;
  1925. }
  1926.  
  1927.  
  1928. ////////////////////////////////////////////////////////////////////////////////
  1929. //
  1930. // PeleFWIMDisableCycleMaster
  1931. //
  1932. //   This routine disables cycle mastering.
  1933. //   Note, this is somewhat redundant, because we will have turned off cycle
  1934. //   mastering at primary interrupt level as soon as we lose root status.  The
  1935. //   only case in which this function would really do anything is if FSL wanted
  1936. //   to stop being the cycle master even though we are the root node.
  1937. //
  1938.  
  1939. static OSStatus PeleFWIMDisableCycleMaster(
  1940.     FWIMCommandParamsPtr        pFWIMCommandParams,
  1941.     UInt32                        *pCommandAcceptance)
  1942. {
  1943.     PeleFWIMDataPtr                pPeleFWIMData;
  1944.     PeleRegistersPtr            pPeleRegs;
  1945.     OSStatus                    status = noErr;
  1946.  
  1947.     // Get our internal data and register base address.
  1948.     pPeleFWIMData = (PeleFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  1949.     pPeleRegs = pPeleFWIMData->pPeleRegisters;
  1950.  
  1951.     // Set pending command.
  1952.     pPeleFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMCommandParams;
  1953.     pPeleFWIMData->pendingFWIMCommandStatus = kPelePendingFWIMCommandBusy;
  1954.  
  1955.     // Disable cycle mastering.
  1956.     pPeleRegs->control &= ~EndianSwapImm32Bit (kPeleControlCycleMaster);
  1957.     SynchronizeIO ();
  1958.  
  1959.     // Finish up command.
  1960.     pPeleFWIMData->pPendingFWIMCommand = nil;
  1961.     status = FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
  1962.  
  1963.     // Return command acceptance.
  1964.     //zzz what if we call FWIMCommandIsComplete before returning this???
  1965.     //zzz well, it still works, but will it always?
  1966.     //zzz actually, when we switch to the dispatch table, each routine can return
  1967.     //zzz the appropriate acceptance, so don't worry about it for now.
  1968.     *pCommandAcceptance = kFWIMCommandAcceptNoMore;
  1969.  
  1970.     return status;
  1971. }
  1972.  
  1973.  
  1974. ////////////////////////////////////////////////////////////////////////////////
  1975. //
  1976. // PeleFWIMSetRootHoldoffBit
  1977. //
  1978. //   This routine sets the PHY root holdoff bit.
  1979. //
  1980.  
  1981. static OSStatus PeleFWIMSetRootHoldoffBit(
  1982.     FWIMCommandParamsPtr        pFWIMCommandParams,
  1983.     UInt32                        *pCommandAcceptance)
  1984. {
  1985.     PeleFWIMDataPtr                pPeleFWIMData;
  1986.     PeleRegistersPtr            pPeleRegs;
  1987.     UInt32                        phyReg;
  1988.     OSStatus                    status = noErr;
  1989.  
  1990.     // Get our internal data and register base address.
  1991.     pPeleFWIMData = (PeleFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  1992.     pPeleRegs = pPeleFWIMData->pPeleRegisters;
  1993.  
  1994.     // Set pending command.
  1995.     pPeleFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMCommandParams;
  1996.     pPeleFWIMData->pendingFWIMCommandStatus = kPelePendingFWIMCommandBusy;
  1997.  
  1998.     // Set the root holdoff bit in the PHY.
  1999.     phyReg = PeleFWIMReadPhyRegister (pPeleFWIMData, pPeleRegs, kPelePhyRHBAddress);
  2000.     phyReg |= kPelePhyRHB;
  2001.     PeleFWIMWritePhyRegister (pPeleRegs, kPelePhyRHBAddress, phyReg);
  2002.  
  2003.     // Finish up command.
  2004.     pPeleFWIMData->pPendingFWIMCommand = nil;
  2005.     status = FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
  2006.  
  2007.     // Return command acceptance.
  2008.     //zzz what if we call FWIMCommandIsComplete before returning this???
  2009.     //zzz well, it still works, but will it always?
  2010.     //zzz actually, when we switch to the dispatch table, each routine can return
  2011.     //zzz the appropriate acceptance, so don't worry about it for now.
  2012.     *pCommandAcceptance = kFWIMCommandAcceptNoMore;
  2013.  
  2014.     return status;
  2015. }
  2016.  
  2017.  
  2018. ////////////////////////////////////////////////////////////////////////////////
  2019. //
  2020. // PeleFWIMClearRootHoldoffBit
  2021. //
  2022. //   This routine clears the PHY root holdoff bit.
  2023. //
  2024.  
  2025. static OSStatus PeleFWIMClearRootHoldoffBit(
  2026.     FWIMCommandParamsPtr        pFWIMCommandParams,
  2027.     UInt32                        *pCommandAcceptance)
  2028. {
  2029.     PeleFWIMDataPtr                pPeleFWIMData;
  2030.     PeleRegistersPtr            pPeleRegs;
  2031.     UInt32                        phyReg;
  2032.     OSStatus                    status = noErr;
  2033.  
  2034.     // Get our internal data and register base address.
  2035.     pPeleFWIMData = (PeleFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  2036.     pPeleRegs = pPeleFWIMData->pPeleRegisters;
  2037.  
  2038.     // Set pending command.
  2039.     pPeleFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMCommandParams;
  2040.     pPeleFWIMData->pendingFWIMCommandStatus = kPelePendingFWIMCommandBusy;
  2041.  
  2042.     // Clear the root holdoff bit in the PHY.
  2043.     phyReg = PeleFWIMReadPhyRegister (pPeleFWIMData, pPeleRegs, kPelePhyRHBAddress);
  2044.     phyReg &= ~kPelePhyRHB;
  2045.     PeleFWIMWritePhyRegister (pPeleRegs, kPelePhyRHBAddress, phyReg);
  2046.  
  2047.     // Finish up command.
  2048.     pPeleFWIMData->pPendingFWIMCommand = nil;
  2049.     status = FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
  2050.  
  2051.     // Return command acceptance.
  2052.     //zzz what if we call FWIMCommandIsComplete before returning this???
  2053.     //zzz well, it still works, but will it always?
  2054.     //zzz actually, when we switch to the dispatch table, each routine can return
  2055.     //zzz the appropriate acceptance, so don't worry about it for now.
  2056.     *pCommandAcceptance = kFWIMCommandAcceptNoMore;
  2057.  
  2058.     return status;
  2059. }
  2060.  
  2061.  
  2062. ////////////////////////////////////////////////////////////////////////////////
  2063. //
  2064. // PeleFWIMGetUniqueID
  2065. //
  2066. //   This routine returns the local unique ID.
  2067. //
  2068.  
  2069. static OSStatus    PeleFWIMGetUniqueID(
  2070.     FWIMGetUniqueIDParamsPtr    pFWIMGetUniqueIDParams,
  2071.     UInt32                        *pCommandAcceptance)
  2072. {
  2073.     PeleFWIMDataPtr                pPeleFWIMData;
  2074.     FWIMCommandParamsPtr        pFWIMCommandParams;
  2075.     OSStatus                    status = noErr;
  2076.     
  2077.     // Get our internal data.
  2078.     pFWIMCommandParams = &(pFWIMGetUniqueIDParams->fwimCommandParams);
  2079.     pPeleFWIMData = (PeleFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  2080.  
  2081. #if 0
  2082.     if (pPeleFWIMData->eepromValid)
  2083.     {
  2084.         pFWIMGetUniqueIDParams->uniqueID.hi = pPeleFWIMData->eepromInfo.busInfoBlock[2];
  2085.         pFWIMGetUniqueIDParams->uniqueID.lo = pPeleFWIMData->eepromInfo.busInfoBlock[3];
  2086.     }
  2087.     else
  2088. #endif
  2089.     {
  2090.         //zzz Fake it
  2091.         pFWIMGetUniqueIDParams->uniqueID.hi = 'pele';
  2092.         pFWIMGetUniqueIDParams->uniqueID.lo = (UInt32) pPeleFWIMData;
  2093.     }
  2094.     
  2095. //    sprintf (debugStr, "PeleFWIMGetUniqueID : Node Vendor ID %06lx   Chip ID %02lx%08lx",
  2096. //             (long) pFWIMGetUniqueIDParams->uniqueID.hi >> 8,
  2097. //             (long) pFWIMGetUniqueIDParams->uniqueID.hi & 0xff,
  2098. //             (long) pFWIMGetUniqueIDParams->uniqueID.lo);
  2099. //    FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  2100.     
  2101.     // Finish up command.
  2102.     pPeleFWIMData->pPendingFWIMCommand = nil;
  2103.     status = FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
  2104.  
  2105.     // Return command acceptance.
  2106.     //zzz what if we call FWIMCommandIsComplete before returning this???
  2107.     //zzz well, it still works, but will it always?
  2108.     //zzz actually, when we switch to the dispatch table, each routine can return
  2109.     //zzz the appropriate acceptance, so don't worry about it for now.
  2110.     *pCommandAcceptance = kFWIMCommandAcceptNoMore;
  2111.  
  2112.     return status;
  2113. }
  2114.  
  2115.  
  2116. ////////////////////////////////////////////////////////////////////////////////
  2117. //
  2118. // PeleFWIMSendLinkOnPacket
  2119. //
  2120. //   This proc sends the given link on packet.
  2121. //
  2122.  
  2123. static OSStatus    PeleFWIMSendLinkOnPacket(
  2124.     FWIMSendPhyPacketParamsPtr    pFWIMSendPhyPacketParams,
  2125.     UInt32                        *pCommandAcceptance)
  2126. {
  2127.     PeleFWIMDataPtr                pPeleFWIMData;
  2128.     FWIMCommandParamsPtr        pFWIMCommandParams;
  2129.     UInt32                        linkOnData;
  2130.     OSStatus                    status = noErr;
  2131.     
  2132.     // Get our internal data.
  2133.     pFWIMCommandParams = &(pFWIMSendPhyPacketParams->fwimCommandParams);
  2134.     pPeleFWIMData = (PeleFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  2135.  
  2136.     // Set pending command.
  2137.     pPeleFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMSendPhyPacketParams;
  2138.     pPeleFWIMData->pendingFWIMCommandStatus = kPelePendingFWIMCommandBusy;
  2139.  
  2140.     // Check if generation is up to date.
  2141.     if ((!(pPeleFWIMData->generationValid)) ||
  2142.         (pFWIMSendPhyPacketParams->generation != pPeleFWIMData->generation))
  2143.     {
  2144.         status = busReconfiguredErr;
  2145.     }
  2146.  
  2147.     // Set up link on data.
  2148.     if (status == noErr)
  2149.     {
  2150.         linkOnData = *((UInt32 *) (pFWIMSendPhyPacketParams->buffer));
  2151.         linkOnData &= ~kFWPhyPacketID;
  2152.         linkOnData |= kFWLinkOnPacketID << kFWPhyPacketIDPhase;
  2153.     }
  2154.     
  2155.     // Send packet.
  2156.     if (status == noErr)
  2157.     {
  2158.         PeleFWIMWriteAT (pPeleFWIMData, kFWSpeed100MBit, 3,
  2159.                          0x0E << kPelePacketTCodePhase,
  2160.                          linkOnData, ~linkOnData, 0, 0, 0);
  2161.     }
  2162.  
  2163.     // Finish up command.
  2164.     pPeleFWIMData->pPendingFWIMCommand = nil;
  2165.     status = FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
  2166.  
  2167.     // Return command acceptance.
  2168.     //zzz what if we call FWIMCommandIsComplete before returning this???
  2169.     //zzz well, it still works, but will it always?
  2170.     //zzz actually, when we switch to the dispatch table, each routine can return
  2171.     //zzz the appropriate acceptance, so don't worry about it for now.
  2172.     *pCommandAcceptance = kFWIMCommandAcceptNoMore;
  2173.  
  2174.     return status;
  2175. }
  2176.  
  2177.  
  2178. ////////////////////////////////////////////////////////////////////////////////
  2179. //
  2180. // PeleFWIMSendPhyConfigurationPacket
  2181. //
  2182. //   This proc sends the given Phy configuration packet.
  2183. //
  2184.  
  2185. static OSStatus    PeleFWIMSendPhyConfigurationPacket(
  2186.     FWIMSendPhyPacketParamsPtr    pFWIMSendPhyPacketParams,
  2187.     UInt32                        *pCommandAcceptance)
  2188. {
  2189.     PeleFWIMDataPtr                pPeleFWIMData;
  2190.     FWIMCommandParamsPtr        pFWIMCommandParams;
  2191.     UInt32                        configurationData;
  2192.     OSStatus                    status = noErr;
  2193.     
  2194.     // Get our internal data.
  2195.     pFWIMCommandParams = &(pFWIMSendPhyPacketParams->fwimCommandParams);
  2196.     pPeleFWIMData = (PeleFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  2197.  
  2198.     // Set pending command.
  2199.     pPeleFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMSendPhyPacketParams;
  2200.     pPeleFWIMData->pendingFWIMCommandStatus = kPelePendingFWIMCommandBusy;
  2201.  
  2202.     // Check if generation is up to date.
  2203.     if ((!(pPeleFWIMData->generationValid)) ||
  2204.         (pFWIMSendPhyPacketParams->generation != pPeleFWIMData->generation))
  2205.     {
  2206.         status = busReconfiguredErr;
  2207.     }
  2208.  
  2209.     // Set up phy configuration data.
  2210.     if (status == noErr)
  2211.     {
  2212.         configurationData = *((UInt32 *) (pFWIMSendPhyPacketParams->buffer));
  2213.         configurationData &= ~kFWPhyPacketID;
  2214.         configurationData |= kFWConfigurationPacketID << kFWPhyPacketIDPhase;
  2215.     }
  2216.     
  2217.     // Send packet.
  2218.     if (status == noErr)
  2219.     {
  2220.         PeleFWIMWriteAT (pPeleFWIMData, kFWSpeed100MBit, 3,
  2221.                          (0x0E << kPelePacketTCodePhase),
  2222.                          configurationData, ~configurationData, 0, 0, 0);
  2223.     }
  2224.  
  2225.     // Finish up command.
  2226.     pPeleFWIMData->pPendingFWIMCommand = nil;
  2227.     status = FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
  2228.  
  2229.     // Return command acceptance.
  2230.     //zzz what if we call FWIMCommandIsComplete before returning this???
  2231.     //zzz well, it still works, but will it always?
  2232.     //zzz actually, when we switch to the dispatch table, each routine can return
  2233.     //zzz the appropriate acceptance, so don't worry about it for now.
  2234.     *pCommandAcceptance = kFWIMCommandAcceptNoMore;
  2235.  
  2236.     return status;
  2237. }
  2238.  
  2239.  
  2240. ////////////////////////////////////////////////////////////////////////////////
  2241. //
  2242. // PeleFWIMWritePhyRegister
  2243. //
  2244. //   This proc writes data to the specified phy register.
  2245. //   There's really no way to confirm the write, so we return immediately.
  2246. //
  2247.  
  2248. static void    PeleFWIMWritePhyRegister(
  2249.     PeleRegistersPtr            pPeleRegs,
  2250.     UInt8                        regAddress,
  2251.     UInt8                        regData)
  2252. {
  2253.     UInt32                        phyChipAccess;
  2254.     AbsoluteTime                absoluteDuration;
  2255.  
  2256. //    FWDebugStr ((ConstStr255Param) "\pPeleFWIMWritePhyRegister");
  2257.  
  2258.     // Set up phyChipAccess to write phy.
  2259.     // Set the write bit, the register address, and data.
  2260.     phyChipAccess = kPelePhyControlWrReg;
  2261.     phyChipAccess |= (regAddress << kPelePhyControlWrAddrPhase);
  2262.     phyChipAccess |= (regData << kPelePhyControlWrDataPhase);
  2263.     pPeleRegs->phyControl = EndianSwap32Bit (phyChipAccess);
  2264.     SynchronizeIO ();
  2265.  
  2266.     // Give it a little time to finish before we try anything else.
  2267.     absoluteDuration = DurationToAbsolute (100 * durationMicrosecond);
  2268.     DelayForHardware (absoluteDuration);
  2269. }
  2270.  
  2271.  
  2272. ////////////////////////////////////////////////////////////////////////////////
  2273. //
  2274. // PeleFWIMReadPhyRegister
  2275. //
  2276. //   This proc reads data from the specified phy register.
  2277. //
  2278. //   Execpt for initialization, this routine is called only from deferred tasks
  2279. //   and/or secondary interrupt level, so it should not re-enter.  Rather than
  2280. //   polling the hardware, we'll wait for the interrupt when a phy register arrives.
  2281. //   lastPhyControl will be updated by an interrupt handler any time a PHY status
  2282. //   transfer sends back a PHY register value.
  2283. //
  2284. //   If PELE_NO_PHY_REG_RCVD is defined, we have to poll the PHY control instead.
  2285.  
  2286. static UInt8    PeleFWIMReadPhyRegister(
  2287.     PeleFWIMDataPtr                pPeleFWIMData,
  2288.     PeleRegistersPtr            pPeleRegs,
  2289.     UInt8                        regAddress)
  2290. {
  2291.     UInt32                        phyChipAccess, phyChipAccessRead;
  2292.     UInt8                        returnedAddress, regData;
  2293.     UInt32                        patience = 100, done = 0;
  2294.     AbsoluteTime                absoluteDuration;
  2295.  
  2296. //    FWDebugStr ((ConstStr255Param) "\pPeleFWIMReadPhyRegister");
  2297.  
  2298.     // Set up phyChipAccessRead to read phy.
  2299.     phyChipAccessRead = kPelePhyControlRdReg;
  2300.     phyChipAccessRead |= (regAddress << kPelePhyControlWrAddrPhase);
  2301.     
  2302.     while (!done)
  2303.     {
  2304.         // Clear the return area and then request a PHY register read.
  2305.         // In normal operation, we should get an answer back in less than a millisecond.
  2306.  
  2307.         (volatile UInt32) (pPeleFWIMData->lastPhyControl) = 0xFFFFFFFF;
  2308.         SynchronizeIO ();
  2309.         pPeleRegs->phyControl = EndianSwap32Bit (phyChipAccessRead);
  2310.         SynchronizeIO ();
  2311.  
  2312.         // This will make the Mac sluggish if there is a storm of resets.
  2313.         absoluteDuration = DurationToAbsolute (durationMillisecond);
  2314.         DelayForHardware (absoluteDuration);
  2315.  
  2316. #ifdef PELE_NO_PHY_REG_RCVD
  2317.         phyChipAccess = pPeleRegs->phyControl;
  2318.         
  2319.         // If rdDone isn't set after a millisecond, it probably never will be.
  2320.         // This will cause us to try again.
  2321.         
  2322.         if (!(phyChipAccess & EndianSwapImm32Bit (kPelePhyControlRdDone)))
  2323.             phyChipAccess = 0xFFFFFFFF;
  2324. #else
  2325.         phyChipAccess = (volatile UInt32) pPeleFWIMData->lastPhyControl;
  2326. #endif
  2327.  
  2328.         if (phyChipAccess == 0xFFFFFFFF)
  2329.         {
  2330.             // No response
  2331.             sprintf (debugStr, "PeleFWIMReadPhyRegister, no response from PHY [%08lx]",
  2332.                      (long) EndianSwap32Bit (pPeleRegs->phyControl));
  2333.             FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  2334.         }
  2335.         else
  2336.         {
  2337.             phyChipAccess = EndianSwap32Bit (phyChipAccess);
  2338.             returnedAddress = (phyChipAccess & kPelePhyControlRdAddr) >> kPelePhyControlRdAddrPhase;
  2339.             
  2340.             if (returnedAddress == regAddress)
  2341.             {
  2342.                 // Got the register we wanted
  2343.                 regData = (phyChipAccess & kPelePhyControlRdData) >> kPelePhyControlRdDataPhase;
  2344.                 done = 1;
  2345.             }
  2346.         }
  2347.         
  2348.         if ((!done) && !(patience--))
  2349.         {
  2350.             done = 1;
  2351.             FWDebugStr ((ConstStr255Param) "\pPeleFWIMReadPhyRegister, PHY seems to be jammed");
  2352.             // set FWIM global failure indication
  2353.         }
  2354.     }
  2355.     
  2356.     return regData;
  2357. }
  2358.  
  2359.  
  2360. ////////////////////////////////////////////////////////////////////////////////
  2361. //
  2362. // PeleFWIMAddAsynchRxDMA
  2363. //
  2364. //   This proc adds a descriptor to the active asynch receive DMA list.
  2365. //
  2366.  
  2367. static void PeleFWIMAddAsynchRxDMA(
  2368.     PeleAsynchRxDMADataPtr        pPeleAsynchRxDMAData)
  2369. {
  2370.     PeleFWIMDataPtr                pPeleFWIMData;
  2371.     PeleAsynchRxDMADataPtr        pPrevPeleAsynchRxDMAData,
  2372.                                 pOverflowPeleAsynchRxDMAData;
  2373.     PeleDMAPtr                    pDMA,
  2374.                                 pPrevDMA,
  2375.                                 pOverflowDMA;
  2376.  
  2377.     // Get PCL data and Pele FWIM data for PCL to add.
  2378.     pDMA = pPeleAsynchRxDMAData->pDMA;
  2379.     pPeleFWIMData = pPeleAsynchRxDMAData->pPeleFWIMData;
  2380.  
  2381.     // Get data for overflow handling.
  2382.     pOverflowPeleAsynchRxDMAData = pPeleFWIMData->asynchRxOverflowDMASegment;
  2383.     pOverflowDMA = pOverflowPeleAsynchRxDMAData->pDMA;
  2384.  
  2385.     // Link new descriptor to overflow handler and invalidate status.
  2386.     pDMA->cmdDep = EndianSwap32Bit ((UInt32) pOverflowPeleAsynchRxDMAData->pDMAPhysical);
  2387.     pDMA->result = EndianSwapImm32Bit (0);
  2388.     pPeleAsynchRxDMAData->pNextRxDMAData = nil;
  2389.  
  2390.     // Get last asynch receive PCL.
  2391.     pPrevPeleAsynchRxDMAData = pPeleFWIMData->pLastAsynchRxDMAData;
  2392.  
  2393.     // Link new PCL to last one.
  2394.     if ((pPrevPeleAsynchRxDMAData != nil) && (pPeleFWIMData->pNextAsynchRxDMAData != nil))
  2395.     {
  2396.         pPrevDMA = pPrevPeleAsynchRxDMAData->pDMA;
  2397.         pPrevDMA->cmdDep = EndianSwap32Bit ((UInt32) pPeleAsynchRxDMAData->pDMAPhysical);
  2398.         pPrevPeleAsynchRxDMAData->pNextRxDMAData = pPeleAsynchRxDMAData;
  2399.     }
  2400.     else
  2401.     {
  2402.         pPeleFWIMData->pNextAsynchRxDMAData = pPeleAsynchRxDMAData;
  2403.     }
  2404.  
  2405.     // Check for overflow.
  2406.     if (pPeleFWIMData->asynchRxOverflowFlag)
  2407.     {
  2408.         // Restart asynch receive PCL program at new PCL if it's still unused.
  2409.         if (pDMA->result == EndianSwapImm32Bit (0))
  2410.             PeleFWIMStartAsynchRxDMAProgram (pPeleFWIMData, pPeleAsynchRxDMAData);
  2411.     }
  2412.  
  2413.     // New PCL is now last.
  2414.     pPeleFWIMData->pLastAsynchRxDMAData = pPeleAsynchRxDMAData;
  2415. }
  2416.  
  2417.  
  2418. ////////////////////////////////////////////////////////////////////////////////
  2419. //
  2420. // PeleFWIMCreateAsynchRxDMAProgram
  2421. //
  2422. //   This proc creates the asynch receive DMA program.
  2423. //
  2424.  
  2425. static void PeleFWIMCreateAsynchRxDMAProgram(
  2426.     PeleFWIMDataPtr                pPeleFWIMData)
  2427. {
  2428.     PeleFWIMDataPtr                pPhysPeleFWIMData;
  2429.     PeleAsynchRxDMADataPtr        pPeleAsynchRxDMAData;
  2430.     PeleDMAPtr                    pDMA;
  2431.     UInt32                        dmaNum,
  2432.                                 packetNum;
  2433.     
  2434.     // Get physical pointer to FWIM data.
  2435.     pPhysPeleFWIMData = pPeleFWIMData->fwimDataPhys;
  2436.  
  2437.     // Create overflow segment.
  2438.     PeleFWIMCreateAsynchRxOverflowDMASegment (pPeleFWIMData);
  2439.  
  2440.     // Create packet descriptors.
  2441.     for (dmaNum = kAsynchRxFirstPacketDMA, packetNum = 0;
  2442.          dmaNum <= kAsynchRxLastPacketDMA;
  2443.          dmaNum++, packetNum++)
  2444.     {
  2445.         // Get pointer to descriptor.
  2446.         pDMA = &(pPeleFWIMData->asynchDMA[dmaNum]);
  2447.  
  2448.         // Add DMA data record.
  2449.         pPeleAsynchRxDMAData = &(pPeleFWIMData->asynchRxDMADataList[dmaNum]);
  2450.         //pPeleAsynchRxDMAData->pNextPCLData will be filled in by AddAsynchRxDMA
  2451.         pPeleAsynchRxDMAData->pPeleFWIMData = pPeleFWIMData;
  2452.         pPeleAsynchRxDMAData->pDMA = pDMA;
  2453.         pPeleAsynchRxDMAData->pDMAPhysical =
  2454.             pPeleFWIMData->asynchDMAPhys + (dmaNum * sizeof (PeleDMA));
  2455.         pPeleAsynchRxDMAData->packetBuffer = pPeleFWIMData->asynchBuf[packetNum];
  2456.         //pPeleAsynchRxDMAData->fwimProcessAsynchParams will be filled in when a packet arrives
  2457.  
  2458.         // Initialize DBDMA descriptor.
  2459.         pDMA->operation =
  2460.             EndianSwapImm32Bit (kPeleINPUT_LAST |            // Entire packet in one buffer
  2461.                                 kPeleKEY_STREAM0 |            // Only STREAM implemented
  2462.                                 kPeleIntAlways |            // Interrupt when done
  2463.                                 kPeleBranchAlways |            // Branch to next descriptor
  2464.                                 kPeleWaitNever |            // No wait
  2465.                                 kAsyncRxPacketBufferSize);    // reqCount
  2466.         pDMA->address = EndianSwap32Bit ((UInt32) pPeleFWIMData->asynchBufPhys[packetNum]);
  2467.         pDMA->cmdDep = EndianSwapImm32Bit (0);        // branch address - will be filled in later.
  2468.         pDMA->result = EndianSwapImm32Bit (0);        // modified when DMA complete
  2469.         
  2470.         // Add descriptor to program.
  2471.         PeleFWIMAddAsynchRxDMA (pPeleAsynchRxDMAData);
  2472.     }
  2473. }
  2474.  
  2475.  
  2476. ////////////////////////////////////////////////////////////////////////////////
  2477. //
  2478. // PeleFWIMCreateAsynchRxOverflowDMASegment
  2479. //
  2480. //   This proc creates the asynch receive overflow DMA segment.
  2481. //zzz what should happen if we get to end of list?
  2482. //
  2483.  
  2484. static void PeleFWIMCreateAsynchRxOverflowDMASegment(
  2485.     PeleFWIMDataPtr                pPeleFWIMData)
  2486. {
  2487.     PeleFWIMDataPtr                pPhysPeleFWIMData;
  2488.     PeleRegistersPtr            pPeleRegs;
  2489.     PeleAsynchRxDMADataPtr        pPeleAsynchRxDMAData;
  2490.     PeleDMAPtr                    pDMA;
  2491.  
  2492.     // This DBDMA goes at the end of the asynch receive program.  If we run out
  2493.     // of asynch receive descriptors, we want to do a controlled shutdown so that we
  2494.     // send the right ack code on any future packets (ack_busyX).  So this program
  2495.     // sets some bits that causes ack_busyX for all packets.  That way, packets don't
  2496.     // pile up in the receive FIFO.
  2497.     
  2498.     // At present, some packets could be in the FIFO by the time we set the busyX
  2499.     // bits.  Those packets will linger there until we recover, and they will
  2500.     // block any incoming isoch packets.  That's not good.  We should add more PCLs
  2501.     // after this one that will drain the FIFO (but not bitbucket the packets).
  2502.         
  2503.     // Get pointer to link registers and physical pointer to FWIM data.
  2504.     pPeleRegs = pPeleFWIMData->pPeleRegisters;
  2505.     pPhysPeleFWIMData = pPeleFWIMData->fwimDataPhys;
  2506.  
  2507.     // Set up program to busy incoming packets.
  2508.     // First STORE_QUAD into the packetControl register to select busyX,
  2509.     //  then STORE_QUAD into pPeleFWIMData so software knows we did this,
  2510.     //  then STOP.
  2511.     // Note, if we ever manipulated the packetControl register, we'd have to update
  2512.     // this program.  But at present, this is the only way we touch packetControl
  2513.     // after initialization.
  2514.     
  2515.     // This assumes that for Pele register addresses, virtual == physical.
  2516.     // For the FWIM data though, we must convert:
  2517.     
  2518.     pPhysPeleFWIMData = pPeleFWIMData->fwimDataPhys;
  2519.     
  2520.     pDMA = &(pPeleFWIMData->asynchDMA[kAsynchRxOverrunDMA]);
  2521.     pPeleAsynchRxDMAData = &(pPeleFWIMData->asynchRxDMADataList[kAsynchRxOverrunDMA]);
  2522.     pPeleAsynchRxDMAData->pPeleFWIMData = pPeleFWIMData;
  2523.     pPeleAsynchRxDMAData->pDMA = pDMA;
  2524.     pPeleAsynchRxDMAData->pDMAPhysical =
  2525.             pPeleFWIMData->asynchDMAPhys + (kAsynchRxOverrunDMA * sizeof (PeleDMA));
  2526.     
  2527.     pDMA->operation = EndianSwapImm32Bit (kPeleSTORE_QUAD |
  2528.                                           kPeleKEY_SYSTEM |        // works on registers too
  2529.                                           4);                    // reqCount
  2530.     pDMA->address = EndianSwap32Bit ((UInt32) &(pPeleRegs->packetControl));
  2531.     pDMA->cmdDep = EndianSwapImm32Bit (kPeleBsyCtrlAlwaysSendBusyX |
  2532.                                        kPelePacketControlRcvSelfID );
  2533.  
  2534.     pDMA++;
  2535.     pDMA->operation = EndianSwapImm32Bit (kPeleSTORE_QUAD |
  2536.                                           kPeleKEY_SYSTEM |
  2537.                                           4);
  2538.     pDMA->address = EndianSwap32Bit ((UInt32) &(pPhysPeleFWIMData->asynchRxOverflowFlag));
  2539.     pDMA->cmdDep = EndianSwapImm32Bit (0xFFFFFFFF);
  2540.  
  2541.     pDMA++;
  2542.     pDMA->operation = EndianSwapImm32Bit (kPeleSTOP_CMD);
  2543.  
  2544.     // Set PCL segment in FWIM data.
  2545.     pPeleFWIMData->asynchRxOverflowDMASegment = pPeleAsynchRxDMAData;
  2546. }
  2547.  
  2548.  
  2549. ////////////////////////////////////////////////////////////////////////////////
  2550. //
  2551. // PeleFWIMStartAsynchRxDMAProgram
  2552. //
  2553. //   This proc starts the asynch receive DMA program.
  2554. //
  2555.  
  2556. static void PeleFWIMStartAsynchRxDMAProgram(
  2557.     PeleFWIMDataPtr                pPeleFWIMData,
  2558.     PeleAsynchRxDMADataPtr        pPeleAsynchRxDMAData)
  2559. {
  2560.     PeleRegistersPtr            pPeleRegs;
  2561.     PeleAsynchRxDMADataPtr        pStartPeleAsynchRxDMAData;
  2562.     Boolean                        asynchRxReady = false;
  2563.  
  2564.     // Get pointer to link registers and start PCL's data.
  2565.     pPeleRegs = pPeleFWIMData->pPeleRegisters;
  2566.  
  2567.     // Check for overflow.
  2568.     if (pPeleFWIMData->asynchRxOverflowFlag)
  2569.     {
  2570.         // Check if we've started priming.
  2571.         if (pPeleFWIMData->numAsynchRxDMAsPrimed == 0)
  2572.         {
  2573.             pPeleFWIMData->pStartAsynchRxDMAData = pPeleAsynchRxDMAData;
  2574.             pPeleFWIMData->numAsynchRxDMAsPrimed = 1;
  2575.         }
  2576.         else
  2577.         {
  2578.             pPeleFWIMData->numAsynchRxDMAsPrimed++;
  2579.         }
  2580.  
  2581.         // Check if we've primed enough receive PCLs.
  2582.         if (pPeleFWIMData->numAsynchRxDMAsPrimed >= kPeleNumAsynchRxDMAsToPrime)
  2583.         {
  2584.             pPeleFWIMData->asynchRxOverflowFlag = 0;
  2585.             pPeleFWIMData->numAsynchRxDMAsPrimed = 0;
  2586.             asynchRxReady = true;
  2587.         }
  2588.     }
  2589.     else
  2590.     {
  2591.         // We're ready to receive.
  2592.         pPeleFWIMData->pStartAsynchRxDMAData = pPeleAsynchRxDMAData;
  2593.         asynchRxReady = true;
  2594.     }
  2595.  
  2596.     if (asynchRxReady)
  2597.     {
  2598.         // Quiet the DMA channel.
  2599.         pPeleRegs->asynchReceive.channelControl = EndianSwapImm32Bit (kPeleClrAll);
  2600.         SynchronizeIO();
  2601.     
  2602.         // Start the program at the given descriptor.
  2603.         pStartPeleAsynchRxDMAData = pPeleFWIMData->pStartAsynchRxDMAData;
  2604.  
  2605.         // Set DMA command pointer
  2606.         pPeleRegs->asynchReceive.commandPtr =
  2607.             EndianSwap32Bit ((UInt32) pStartPeleAsynchRxDMAData->pDMAPhysical);
  2608.         SynchronizeIO();
  2609.             
  2610.         // Enable the DMA.
  2611.         pPeleRegs->asynchReceive.channelControl = EndianSwapImm32Bit (kPeleSetRun);
  2612.         SynchronizeIO();
  2613.     
  2614.         // Clear busy flag in packetControl register.
  2615.         // Only we clear this, only the DMA sets this.
  2616.         // Until we clear this, nothing will arrive in the DMA, so there's no race.
  2617.         pPeleRegs->packetControl = EndianSwapImm32Bit (kPelePacketControlRcvSelfID);        
  2618.     }
  2619. }
  2620.  
  2621.  
  2622. ////////////////////////////////////////////////////////////////////////////////
  2623. //
  2624. // PeleFWIMAddAsynchTxDMA
  2625. //
  2626. //   This proc adds a DMA to the active asynch transmit DMA list.
  2627. //
  2628.  
  2629. static void PeleFWIMAddAsynchTxDMA(
  2630.     PeleAsynchTxDMADataPtr        pTxDMAData)
  2631. {
  2632.     PeleFWIMDataPtr                pPeleFWIMData;
  2633.     PeleAsynchTxDMADataPtr        pPrevTxDMAData,
  2634.                                 pDoneTxDMAData;
  2635.     PeleDMAPtr                    pDMA,
  2636.                                 pPrevDMA,
  2637.                                 pDoneDMA;
  2638.  
  2639.     // Get PCL data and Pele FWIM data for PCL to add.
  2640.     pDMA = pTxDMAData->pDMA;
  2641.     pPeleFWIMData = pTxDMAData->pPeleFWIMData;
  2642.  
  2643.     // Get PCL and PCL data for done handling.
  2644.     pDoneTxDMAData = pPeleFWIMData->asynchTxDoneDMASegment;
  2645.     pDoneDMA = pDoneTxDMAData->pDMA;
  2646.  
  2647.     // Link new PCL to done handler and invalidate new PCL's status.
  2648. //zzz this is done by BuildAsyncTxDMA, because the final point can vary.
  2649. //    pDMA->cmdDep = EndianSwap32Bit ((UInt32) pDoneTxDMAData->pDMAPhysical);
  2650. //    pDMA->operation |= EndianSwapImm32Bit (kPeleBranchAlways);
  2651.     pTxDMAData->pNextTxDMAData = nil;
  2652. // duplicate? zzz
  2653.     pDMA->result = EndianSwapImm32Bit (0);
  2654.  
  2655.     // Get last asynch transmit PCL.
  2656.     pPrevTxDMAData = pPeleFWIMData->pLastAsynchTxDMAData;
  2657.  
  2658.     // Link new PCL to last one.
  2659.     if ((pPrevTxDMAData != nil) && (pPeleFWIMData->pNextAsynchTxDMAData != nil))
  2660.     {
  2661.         pPrevDMA = pPrevTxDMAData->pDMA;
  2662.         pPrevDMA->cmdDep = EndianSwap32Bit ((UInt32) pTxDMAData->pDMAPhysical);
  2663.         pPrevTxDMAData->pNextTxDMAData = pTxDMAData;
  2664.     }
  2665.     else
  2666.     {
  2667.         pPeleFWIMData->pNextAsynchTxDMAData = pTxDMAData;
  2668.     }
  2669.  
  2670.     // Check for asynchronous transmit done.
  2671.     if (pPeleFWIMData->asynchTxDoneFlag)
  2672.     {
  2673.         // Restart asynch transmit PCL program at new PCL if it's still unused.
  2674.         if (pDMA->result == EndianSwapImm32Bit (0))
  2675.             PeleFWIMStartAsynchTxDMAProgram (pPeleFWIMData, pTxDMAData);
  2676.     }
  2677.  
  2678.     // New PCL is now last.
  2679.     pPeleFWIMData->pLastAsynchTxDMAData = pTxDMAData;
  2680. }
  2681.  
  2682.  
  2683. ////////////////////////////////////////////////////////////////////////////////
  2684. //
  2685. // PeleFWIMCreateAsynchTxDoneDMASegment
  2686. //
  2687. //   This proc creates the asynch transmit done DMA segment.
  2688. //
  2689.  
  2690. static void PeleFWIMCreateAsynchTxDoneDMASegment(
  2691.     PeleFWIMDataPtr                pPeleFWIMData)
  2692. {
  2693.     PeleFWIMDataPtr                pPhysPeleFWIMData;
  2694.     PeleAsynchTxDMADataPtr        pTxDMAData;
  2695.     PeleDMAPtr                    pDMA;
  2696.  
  2697.     // Get physical pointer to FWIM data.
  2698.     pPhysPeleFWIMData = pPeleFWIMData->fwimDataPhys;
  2699.  
  2700.     // need two descriptors - store quad and STOP.
  2701.  
  2702.     // Set up descriptors to set done flag.
  2703.     pDMA = &(pPeleFWIMData->asynchXmitDMA[kAsynchTxDoneDMA]);
  2704.     pDMA->operation = EndianSwapImm32Bit (kPeleSTORE_QUAD |
  2705.                                           kPeleKEY_SYSTEM |
  2706.                                           kPeleIntNever |
  2707.                                           kPeleBranchNever |
  2708.                                           kPeleWaitNever |
  2709.                                           4);        // reqCount
  2710.     pDMA->address = EndianSwap32Bit ((UInt32) &(pPhysPeleFWIMData->asynchTxDoneFlag));
  2711.     pDMA->cmdDep = EndianSwapImm32Bit (0xFFFFFFFF);
  2712.     pDMA->result = EndianSwapImm32Bit (0);
  2713.     
  2714.     pDMA = &(pPeleFWIMData->asynchXmitDMA[kAsynchTxDoneDMA + 1]);
  2715.     pDMA->operation = EndianSwapImm32Bit (kPeleSTOP_CMD |
  2716.                                           kPeleIntNever |
  2717.                                           kPeleBranchNever |
  2718.                                           kPeleWaitNever);
  2719.     pDMA->address = EndianSwapImm32Bit (0);
  2720.     pDMA->cmdDep = EndianSwapImm32Bit (0);
  2721.     pDMA->result = EndianSwapImm32Bit (0);
  2722.     
  2723.     pTxDMAData = &(pPeleFWIMData->AsynchTxDMADataList[kAsynchTxDoneDMA]);
  2724.     pTxDMAData->pPeleFWIMData = pPeleFWIMData;
  2725.     pTxDMAData->pDMA = &(pPeleFWIMData->asynchXmitDMA[kAsynchTxDoneDMA]);
  2726.     pTxDMAData->pDMAPhysical =
  2727.         pPeleFWIMData->asynchXmitDMAPhys + (kAsynchTxDoneDMA * sizeof (PeleDMA));
  2728.  
  2729.     // Set done flag.
  2730.     pPeleFWIMData->asynchTxDoneFlag = 0xFFFFFFFF;
  2731.     pPeleFWIMData->pLastAsynchTxDMAData = nil;
  2732.     
  2733.     // Note in FWIM data.
  2734.     pPeleFWIMData->asynchTxDoneDMASegment = pTxDMAData;
  2735. }
  2736.  
  2737.  
  2738. ////////////////////////////////////////////////////////////////////////////////
  2739. //
  2740. // PeleFWIMCreateAsynchTxDataDMA
  2741. //
  2742. //   This proc creates a data DMA for the asynch transmit DMA program.
  2743. //
  2744.  
  2745. static void PeleFWIMCreateAsynchTxDataDMA(
  2746.     PeleFWIMDataPtr                pPeleFWIMData)
  2747. {
  2748.     PeleAsynchTxDMADataPtr        pTxDMAData;
  2749.  
  2750.     // Just fill in the basics.
  2751.     // This single data pointer points to a block of consecutive descriptors.
  2752.     
  2753.     pTxDMAData = &(pPeleFWIMData->AsynchTxDMADataList[kAsynchTxDataDMA]);
  2754.     pTxDMAData->pPeleFWIMData = pPeleFWIMData;
  2755.     pTxDMAData->pDMA = &(pPeleFWIMData->asynchXmitDMA[kAsynchTxDataDMA]);
  2756.     pTxDMAData->pDMAPhysical =
  2757.         pPeleFWIMData->asynchXmitDMAPhys + (kAsynchTxDataDMA * sizeof (PeleDMA));
  2758. }
  2759.  
  2760.  
  2761. ////////////////////////////////////////////////////////////////////////////////
  2762. //
  2763. // PeleFWIMStartAsynchTxDMAProgram
  2764. //
  2765. //   This proc starts the asynch transmit DMA program.
  2766. //
  2767.  
  2768. static void PeleFWIMStartAsynchTxDMAProgram(
  2769.     PeleFWIMDataPtr                pPeleFWIMData,
  2770.     PeleAsynchTxDMADataPtr        pStartTxDMAData)
  2771. {
  2772.     PeleRegistersPtr            pPeleRegs = pPeleFWIMData->pPeleRegisters;
  2773.  
  2774.     // Clear done flag.
  2775.     pPeleFWIMData->asynchTxDoneFlag = 0;
  2776.  
  2777.     // Clear ack status in end segment.
  2778.     pPeleFWIMData->asynchTxDoneDMASegment->pDMA->result = EndianSwapImm32Bit (0);
  2779.  
  2780.     // Quiet the DMA channel.
  2781.     pPeleRegs->asynchTransmit.channelControl = EndianSwapImm32Bit (kPeleClrAll);
  2782.     SynchronizeIO();
  2783.  
  2784.     // Start the program at the given descriptor.
  2785.     pPeleRegs->asynchTransmit.commandPtr =
  2786.         EndianSwap32Bit ((UInt32) pStartTxDMAData->pDMAPhysical);
  2787.     SynchronizeIO();
  2788.  
  2789.     // Enable the DMA.
  2790.     pPeleRegs->asynchTransmit.channelControl = EndianSwapImm32Bit (kPeleSetRun);
  2791.     SynchronizeIO();
  2792. }
  2793.  
  2794.  
  2795. ////////////////////////////////////////////////////////////////////////////////
  2796. //
  2797. // PeleFWIMWriteAT
  2798. //
  2799. //   Common code for writing an ATF packet
  2800. //
  2801.  
  2802. static OSStatus PeleFWIMWriteAT(
  2803.     PeleFWIMDataPtr                pPeleFWIMData,
  2804.     UInt32                        speed,
  2805.     UInt32                        baseCount,        // count [1-4] of quads below:
  2806.     UInt32                        data1,
  2807.     UInt32                        data2,
  2808.     UInt32                        data3,
  2809.     UInt32                        data4,
  2810.     UInt32                        extCount,        // count in BYTES of data below:
  2811.     UInt32                        *extData)
  2812. {
  2813.     PeleRegistersPtr            pPeleRegs;
  2814.     IOPreparationID                ioPreparationID;
  2815.     UInt32                        dataBuffer[4];
  2816.     AbsoluteTime                timeoutAbsolute, timeLeft;
  2817.     UInt32                        patience;
  2818.     OSStatus                    status = noErr;
  2819.  
  2820.     // Get pointer to link registers.
  2821.     pPeleRegs = pPeleFWIMData->pPeleRegisters;
  2822.  
  2823.     // Set up descriptor.
  2824.     dataBuffer[0] = data1;
  2825.     dataBuffer[1] = data2;
  2826.     dataBuffer[2] = data3;
  2827.     dataBuffer[3] = data4;
  2828.  
  2829.     // If we queued multiple transmits, this would matter.  But we only send one
  2830.     // packet at a time.  We could get a bus reset just before we activate the
  2831.     // transmitter, but there's nothing we can do in software to avoid that.
  2832.     
  2833.     // Note, some older Pele designs don't use the EnableAT bit in the ATDMA.
  2834.     // Setting it should be harmless (and useless) on such parts.
  2835.     
  2836.     dataBuffer[0] |= kPelePacketEnableAT;
  2837.  
  2838.     // This assumes that baseCount is at least 1.  All async DMA puts the speed here:
  2839.     
  2840.     if (speed == kFWSpeed200MBit)
  2841.         dataBuffer[0] |= (kPeleDMA200mbps << kPelePacketSpdPhase);
  2842.         
  2843.     if (speed == kFWSpeed400MBit)
  2844.         dataBuffer[0] |= (kPeleDMA400mbps << kPelePacketSpdPhase);
  2845.  
  2846.     dataBuffer[0] |= kPelePacketEnableAT;        //zzz Not sure there's any better way
  2847.         
  2848.     PeleFWIMBuildAsynchTxDMA (pPeleFWIMData,
  2849.                              &(pPeleFWIMData->AsynchTxDMADataList[kAsynchTxDataDMA]),
  2850.                              &ioPreparationID,
  2851.                              (Ptr) &dataBuffer[0],
  2852.                              baseCount * sizeof (UInt32),
  2853.                              (Ptr) extData,
  2854.                              extCount);
  2855.  
  2856.     // Add data PCL to asynch transmit program and start.
  2857.     PeleFWIMAddAsynchTxDMA (&(pPeleFWIMData->AsynchTxDMADataList[kAsynchTxDataDMA]));
  2858.  
  2859.     // This still isn't great.  We should just return, and then handle completion or
  2860.     // failure later, when an interrupt or timer goes off.
  2861.     
  2862.     // Wait for asynch transmit program to end, or TX to be disabled (due to bus reset).
  2863.     // Check TX disable only once per millisecond.  Try this for at most 50 milliseconds.
  2864.  
  2865.     timeoutAbsolute =
  2866.         AddAbsoluteToAbsolute (UpTime (), DurationToAbsolute (durationMillisecond));
  2867.     patience = 50;
  2868.  
  2869.     while (!(pPeleFWIMData->asynchTxDoneFlag))
  2870.     {
  2871.         // It's probably not necessary to do this any more.  The reset primary handler
  2872.         // Will stop the DMA and mark it as done if there is a bus reset while we try
  2873.         // to transmit.
  2874.         // Check only rarely for bus reset
  2875.         timeLeft = SubAbsoluteFromAbsolute (UpTime (), timeoutAbsolute);  // returns 0 if negative
  2876.         if (AbsoluteToDuration (timeLeft) == 0)        
  2877.         {
  2878.             if ((!patience) || !(EndianSwap32Bit(pPeleRegs->control) & kPeleControlTransmitEnable))
  2879.             {
  2880.                 pPeleRegs->asynchTransmit.channelControl = EndianSwapImm32Bit (kPeleClrAll);
  2881.                 SynchronizeIO ();
  2882.                 pPeleFWIMData->asynchTxDoneFlag = 0xFFFFFFFF;
  2883.             }
  2884.             else
  2885.             {
  2886.                 timeoutAbsolute =
  2887.                     AddAbsoluteToAbsolute (UpTime (), DurationToAbsolute (durationMillisecond));
  2888.                 patience--;
  2889.             }        
  2890.         }
  2891.     }
  2892.     
  2893.     // Clean up transmission.
  2894.     CheckpointIO (ioPreparationID, kNilOptions);
  2895.     
  2896.     // Streaming is NYI, so this is always nil.
  2897.     pPeleFWIMData->pNextAsynchTxDMAData =
  2898.         pPeleFWIMData->AsynchTxDMADataList[kAsynchTxDataDMA].pNextTxDMAData;
  2899.  
  2900.     return status;
  2901. }
  2902.  
  2903.  
  2904. ////////////////////////////////////////////////////////////////////////////////
  2905. //
  2906. // PeleFWIMBuildAsynchTxDMA
  2907. //
  2908. //   This proc builds an asynchronous transmit PCL from the given parameters.
  2909. // buffer1 is assumed to be small.  It is usually a packet header.  buffer2 is
  2910. // assumed to be larger and typically is a packet payload.
  2911. //
  2912.  
  2913. static OSStatus    PeleFWIMBuildAsynchTxDMA(
  2914.     PeleFWIMDataPtr                pPeleFWIMData,
  2915.     PeleAsynchTxDMADataPtr        pTxDMAData,
  2916.     IOPreparationID                *pIOPreparationID,
  2917.     Ptr                            buffer1,
  2918.     UInt32                        size1,
  2919.     Ptr                            buffer2,
  2920.     UInt32                        size2)
  2921. {
  2922.     IOPreparationTable            ioPreparationTable;
  2923.     PeleDMAPtr                    pDMA;
  2924.     PhysicalAddress                physicalMapping[kMaxBufPage];
  2925.     UInt32                        pageSize,
  2926.                                 pageShift;
  2927.     UInt32                        numPages;
  2928.     Ptr                            preparedBuffer;
  2929.     UInt32                        seg1Size,
  2930.                                 seg2Size;
  2931.     UInt32                        seg2AlignSize;
  2932.     UInt32                        transferSize;
  2933.     UInt32                        dmaBufferNum;
  2934.     UInt32                        pageNum;
  2935.     OSStatus                    status = noErr;
  2936.  
  2937.     // Get some FWIM parameters.
  2938.     pageSize = pPeleFWIMData->pageSize;
  2939.     pageShift = pPeleFWIMData->pageShift;
  2940.     preparedBuffer = pPeleFWIMData->asynchXmitBuf;
  2941.  
  2942.     // Do initial DMA set up.
  2943.     pDMA = pTxDMAData->pDMA;
  2944.     pDMA->result = EndianSwapImm32Bit (0);
  2945.  
  2946.     // Set up initial segment sizes, PCL buffer number, and ioPreparationTable.
  2947.     seg1Size = size1;
  2948.     seg2Size = size2;
  2949.     dmaBufferNum = 0;
  2950.     ioPreparationTable.preparationID = kInvalidID;
  2951.  
  2952.     // Add buffer1 to our prepared buffer.
  2953.     if (size1 > 0)
  2954.     {
  2955.         BlockCopy (buffer1, preparedBuffer, size1);
  2956.         preparedBuffer += size1;
  2957.     }
  2958.  
  2959.     // Add data from buffer2 to our prepared buffer to 32 byte align second segment.
  2960.     if ((((UInt32) buffer2) & 31) > 0)
  2961.         seg2AlignSize = 32 - (((UInt32) buffer2) & 31);
  2962.     else
  2963.         seg2AlignSize = 0;
  2964.     if (seg2AlignSize > size2)
  2965.         seg2AlignSize = size2;
  2966.     if (seg2AlignSize > 0)
  2967.     {
  2968.         BlockCopy (buffer2, preparedBuffer, seg2AlignSize);
  2969.         preparedBuffer += seg2AlignSize;
  2970.         seg1Size += seg2AlignSize;
  2971.         buffer2 += seg2AlignSize;
  2972.         seg2Size -= seg2AlignSize;
  2973.     }
  2974.  
  2975.     // Add prepared buffer to PCL.
  2976.     pDMA->operation = EndianSwap32Bit ((seg2Size ? kPeleOUTPUT_MORE : kPeleOUTPUT_LAST) |
  2977.                                        kPeleKEY_STREAM0 |
  2978.                                        kPeleIntNever |
  2979.                                        kPeleBranchNever |
  2980.                                        kPeleWaitNever |
  2981.                                        seg1Size);
  2982.     pDMA->address = EndianSwap32Bit ((UInt32) pPeleFWIMData->asynchXmitBufPhys);
  2983.     pDMA->cmdDep = EndianSwapImm32Bit (0);
  2984.     pDMA->result = EndianSwapImm32Bit (0);
  2985.     
  2986.     pDMA++;
  2987.     dmaBufferNum++;
  2988.  
  2989.     // Add rest of buffer2 to PCL.
  2990.     if (seg2Size > 0)
  2991.     {
  2992.         // Set up IO preparation table.
  2993.         numPages = ((((UInt32) buffer2) + seg2Size - 1) >> pageShift) -
  2994.                    (((UInt32) buffer2) >> pageShift) + 1;
  2995.         ioPreparationTable.options = kIOLogicalRanges | kIOIsOutput;
  2996.         ioPreparationTable.addressSpace = kCurrentAddressSpaceID;
  2997.         ioPreparationTable.granularity = 0;
  2998.         ioPreparationTable.firstPrepared = 0;
  2999.         ioPreparationTable.mappingEntryCount = numPages;
  3000.         ioPreparationTable.logicalMapping = 0;
  3001.         ioPreparationTable.physicalMapping = physicalMapping;
  3002.         ioPreparationTable.rangeInfo.range.base = buffer2;
  3003.         ioPreparationTable.rangeInfo.range.length = seg2Size;
  3004.  
  3005.         // Prepare.
  3006.         status = PrepareMemoryForIO (&ioPreparationTable);
  3007.     /*zzz*/
  3008.         if (status != noErr)
  3009.         {
  3010.             sprintf (debugStr, "PrepareMemoryForIO error %ld", status);
  3011.             FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  3012.         }
  3013.     /*zzz*/
  3014.  
  3015.         // Add pages to PCL.
  3016.         if (status == noErr)
  3017.         {
  3018.             // Compute first page transfer size.
  3019.             if (numPages > 1)
  3020.                 transferSize = pageSize - (((UInt32) buffer2) & (pageSize - 1));
  3021.             else
  3022.                 transferSize = seg2Size;
  3023.  
  3024.             // Add first page to PCL.
  3025.             pDMA->operation = EndianSwap32Bit ((numPages > 1 ?
  3026.                                                     kPeleOUTPUT_MORE : kPeleOUTPUT_LAST) |
  3027.                                                kPeleKEY_STREAM0 |
  3028.                                                kPeleIntNever |
  3029.                                                kPeleBranchNever |
  3030.                                                kPeleWaitNever |
  3031.                                                transferSize);
  3032.             pDMA->address = EndianSwap32Bit ((UInt32) physicalMapping[0]);
  3033.             pDMA->cmdDep = EndianSwapImm32Bit (0);
  3034.             pDMA->result = EndianSwapImm32Bit (0);
  3035.             
  3036.             pDMA++;
  3037.             dmaBufferNum++;
  3038.  
  3039.             // Add rest of pages except last one to PCL.
  3040.             for (pageNum = 1; pageNum < (numPages - 1); pageNum++)
  3041.             {
  3042.                 // Add page to PCL.
  3043.                 pDMA->operation = EndianSwap32Bit (kPeleOUTPUT_MORE |
  3044.                                                    kPeleKEY_STREAM0 |
  3045.                                                    kPeleIntNever |
  3046.                                                    kPeleBranchNever |
  3047.                                                    kPeleWaitNever |
  3048.                                                    pageSize);
  3049.                 pDMA->address = EndianSwap32Bit ((UInt32) physicalMapping[pageNum]);
  3050.                 pDMA->cmdDep = EndianSwapImm32Bit (0);
  3051.                 pDMA->result = EndianSwapImm32Bit (0);
  3052.  
  3053.                 pDMA++;
  3054.                 dmaBufferNum++;
  3055.             }
  3056.  
  3057.             // Add last page to PCL.
  3058.             if (numPages > 1)
  3059.             {
  3060.                 transferSize = (((UInt32) buffer2) + seg2Size) & (pageSize - 1);
  3061.                 pDMA->operation = EndianSwap32Bit (kPeleOUTPUT_LAST |
  3062.                                                    kPeleKEY_STREAM0 |
  3063.                                                    kPeleIntNever |
  3064.                                                    kPeleBranchNever |
  3065.                                                    kPeleWaitNever |
  3066.                                                    transferSize);
  3067.                 pDMA->address = EndianSwap32Bit ((UInt32) physicalMapping[numPages - 1]);
  3068.                 pDMA->cmdDep = EndianSwapImm32Bit (0);
  3069.                 pDMA->result = EndianSwapImm32Bit (0);
  3070.                 
  3071.                 pDMA++;
  3072.                 dmaBufferNum++;
  3073.             }
  3074.         }
  3075.     }
  3076.  
  3077.     // Mark final descriptor to branch to done segment
  3078.     pDMA--;
  3079.     pDMA->operation |= EndianSwapImm32Bit (kPeleBranchAlways);
  3080.     pDMA->cmdDep = EndianSwap32Bit ((UInt32) pPeleFWIMData->asynchTxDoneDMASegment->pDMAPhysical);
  3081.     
  3082.     // Return ioPreparationID.
  3083.     if (status == noErr)
  3084.         *pIOPreparationID = ioPreparationTable.preparationID;
  3085.     else
  3086.         *pIOPreparationID = kInvalidID;
  3087.  
  3088.     return status;
  3089. }
  3090.  
  3091.  
  3092. ////////////////////////////////////////////////////////////////////////////////
  3093. //
  3094. // PeleFWIMRead
  3095. //
  3096. //   This proc performs a read transaction on the FireWire bus.
  3097. //   We write the read command, the completion is handled elsewhere
  3098. //   when we get an interrupt for the receipt of the response.
  3099. //zzz what if timer goes off before request goes out???
  3100. //zzz check length against maximum packet size
  3101. //zzz should be set up to get acknowledgement
  3102. //
  3103.  
  3104. static OSStatus    PeleFWIMRead(
  3105.     FWIMAsynchCommandParamsPtr    pFWIMAsynchCommandParams,
  3106.     UInt32                        *pCommandAcceptance)
  3107. {
  3108.     FWIMCommandParamsPtr        pFWIMCommandParams;
  3109.     PeleFWIMDataPtr                pPeleFWIMData; 
  3110.     UInt32                        data1, data2, data3, data4;
  3111.     AbsoluteTime                timeoutAbsolute;
  3112.     OSStatus                    status = noErr;
  3113.  
  3114. //    FWDebugStr ((ConstStr255Param) "\p(Pele) PeleFWIMRead");
  3115.  
  3116.     // Get our internal data.
  3117.     pFWIMCommandParams = &(pFWIMAsynchCommandParams->fwimCommandParams);
  3118.     pPeleFWIMData = (PeleFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  3119.  
  3120.     // Set pending command.
  3121.     pPeleFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMAsynchCommandParams;
  3122.     pPeleFWIMData->pendingFWIMCommandStatus = kPelePendingFWIMCommandBusy;
  3123.  
  3124.     // Check if generation is up to date.
  3125.     if ((!(pPeleFWIMData->generationValid)) ||
  3126.         (pFWIMAsynchCommandParams->generation != pPeleFWIMData->generation))
  3127.     {
  3128.         status = busReconfiguredErr;
  3129.     }
  3130.  
  3131. // Warning - it is ESSENTIAL that reads which fail trigger the timeout handler.
  3132. // FSL can't handle reads that just "vanish".  But, rather than go thru the handler,
  3133. // maybe we can return a failure below.
  3134.  
  3135. //    FWDebugStr ((ConstStr255Param) "\pPeleFWIMRead - setting timer for failure");
  3136.     // Set a timeout timer.
  3137.     if (status == noErr)
  3138.     {
  3139.         timeoutAbsolute = AddAbsoluteToAbsolute (UpTime (), DurationToAbsolute (pFWIMAsynchCommandParams->timeout));
  3140.         status = SetInterruptTimer
  3141.                     (&timeoutAbsolute,
  3142.                      PeleFWIMReadRequestTimeoutHandler,
  3143.                      pFWIMAsynchCommandParams,
  3144.                      &(pPeleFWIMData->requestTimeoutTimerID));
  3145.         if (status == noErr)
  3146.             pPeleFWIMData->requestTimeoutTimerSet = true;
  3147.     }
  3148.  
  3149. // sometimes FSL tries to read from the local node, which won't work.
  3150. // rather than bothering the DMA engine, just let the timeout timer
  3151. // return the error.  (return now - NYI)
  3152.  
  3153.     // Write read request to ATF.
  3154.     if (status == noErr)
  3155.     {
  3156. // Need to send at correct speed (WriteAFT always sends at 100)
  3157.         pPeleFWIMData->transactionLabel =
  3158.             (pPeleFWIMData->transactionLabel + 1) & 0x3F;
  3159.  
  3160.         // Header quad common to quadlet and block:
  3161.         data1 = pPeleFWIMData->transactionLabel << kPeleAsynchTLabelPhase;
  3162.         data1 |= (kPeleAsynchNew << kPeleAsynchRtPhase);
  3163.         
  3164.         // Packet address same for both:
  3165.         data2 = pFWIMAsynchCommandParams->addressHi;
  3166.         data3 = pFWIMAsynchCommandParams->addressLo;
  3167.         
  3168.         if (pFWIMAsynchCommandParams->length == 4)
  3169.         { // Quadlet request.
  3170.                         
  3171.             pPeleFWIMData->tCode = kFWTCodeReadQuadlet;
  3172.             data1 |= (kFWTCodeReadQuadlet << kPelePacketTCodePhase);
  3173.  
  3174.             PeleFWIMWriteAT(pPeleFWIMData, pFWIMAsynchCommandParams->speed, 3, data1, data2, data3, 0, 0, 0);
  3175.         }
  3176.         else
  3177.         { // Block request.
  3178.  
  3179.             pPeleFWIMData->tCode = kFWTCodeReadBlock;
  3180.             data1 |= (kFWTCodeReadBlock << kPelePacketTCodePhase);
  3181.  
  3182.             data4 = pFWIMAsynchCommandParams->length << kPeleAsynchDataLengthPhase;
  3183.             
  3184.             PeleFWIMWriteAT(pPeleFWIMData, pFWIMAsynchCommandParams->speed, 4, data1, data2, data3, data4, 0, 0);
  3185.         }
  3186.     }
  3187.  
  3188.     // Complete command on error.
  3189.     if (status != noErr)
  3190.     {
  3191.         pPeleFWIMData->pPendingFWIMCommand = nil;
  3192.         status = FWIMCommandIsComplete
  3193.                     (pFWIMAsynchCommandParams->fwimCommandParams.fwimCommandID,
  3194.                      status);
  3195.     }
  3196.  
  3197.     // Return command acceptance.
  3198.     //zzz what if we call FWIMCommandIsComplete before returning this???
  3199.     //zzz well, it still works, but will it always?
  3200.     //zzz actually, when we switch to the dispatch table, each routine can return
  3201.     //zzz the appropriate acceptance, so don't worry about it for now.
  3202.     *pCommandAcceptance = kFWIMCommandAcceptNoMore;
  3203.  
  3204.     return status;
  3205. }
  3206.  
  3207.  
  3208. ////////////////////////////////////////////////////////////////////////////////
  3209. //
  3210. // PeleFWIMReadResponse
  3211. //
  3212. //   This proc sends a read response packet.
  3213. //zzz check length against maximum packet size
  3214. //zzz should be set up to get acknowledgement
  3215. //
  3216.  
  3217. static OSStatus    PeleFWIMReadResponse(
  3218.     FWIMAsynchResponseCommandParamsPtr
  3219.                                 pFWIMAsynchResponseCommandParams,
  3220.     UInt32                        *pCommandAcceptance)
  3221. {
  3222.     FWIMCommandParamsPtr        pFWIMCommandParams;
  3223.     PeleFWIMDataPtr                pPeleFWIMData; 
  3224.     UInt32                        data1, data2, data4;
  3225.     UInt32                        transactionLabel;
  3226.     UInt32                        responseCode;
  3227.     OSStatus                    status = noErr;
  3228.  
  3229.     // Get our internal data.
  3230.     pFWIMCommandParams = &(pFWIMAsynchResponseCommandParams->fwimCommandParams);
  3231.     pPeleFWIMData = (PeleFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  3232.  
  3233.     // Set pending command.
  3234.     pPeleFWIMData->pPendingFWIMResponseCommand =
  3235.         (FWIMCommandParamsPtr) pFWIMAsynchResponseCommandParams;
  3236.  
  3237.     // Check if generation is up to date.
  3238.     if ((!(pPeleFWIMData->generationValid)) ||
  3239.         (pFWIMAsynchResponseCommandParams->generation != pPeleFWIMData->generation))
  3240.     {
  3241.         status = busReconfiguredErr;
  3242.     }
  3243.  
  3244.     // Write read response to ATF.
  3245.     if (status == noErr)
  3246.     {
  3247.         // Compute transaction label and response code.
  3248.         transactionLabel = (pFWIMAsynchResponseCommandParams->transactionDescriptor &
  3249.                             kFWTransactionDescriptorTLabel) >>
  3250.                            kFWTransactionDescriptorTLabelPhase;
  3251.         responseCode = (pFWIMAsynchResponseCommandParams->responseDataHi &
  3252.                         kFWResponseDataRCode) >>
  3253.                        kFWResponseDataRCodePhase;
  3254.  
  3255.         // packet control header goes in quad 1
  3256.         data1 = transactionLabel << kPeleAsynchTLabelPhase;
  3257.         data1 |= kPeleAsynchNew << kPeleAsynchRtPhase;
  3258.     
  3259.         // packet destination node ID and response code go in quad 2
  3260.         data2 = pFWIMAsynchResponseCommandParams->destinationID << kPeleAsynchSourceIDPhase;
  3261.         data2 |= responseCode << kPeleAsynchRCodePhase;
  3262.     
  3263.         // packet payload goes in quad 4
  3264.         data4 = (*((UInt32 *) pFWIMAsynchResponseCommandParams->buffer));
  3265.     
  3266.         if (pFWIMAsynchResponseCommandParams->length == 4)
  3267.         { // Quadlet request.
  3268.                         
  3269.             data1 |= kFWTCodeReadQuadletResponse << kPelePacketTCodePhase;
  3270.  
  3271.             PeleFWIMWriteAT(pPeleFWIMData, pFWIMAsynchResponseCommandParams->speed, 4, data1, data2, 0, data4, 0, 0);
  3272.         }
  3273.         else
  3274.         { // Block request.
  3275.  
  3276.             data1 |= kFWTCodeReadBlockResponse << kPelePacketTCodePhase;
  3277.  
  3278.             data4 = pFWIMAsynchResponseCommandParams->length << kPeleAsynchDataLengthPhase;
  3279.             
  3280.             PeleFWIMWriteAT(pPeleFWIMData, pFWIMAsynchResponseCommandParams->speed, 4, data1, data2, 0, data4, pFWIMAsynchResponseCommandParams->length, (UInt32 *) pFWIMAsynchResponseCommandParams->buffer);
  3281.         }
  3282.     }
  3283.  
  3284.     // Complete command on error.
  3285.     //zzz assume success for now.  should check ack code for success.
  3286. //zzz    if (status != noErr)
  3287.     {
  3288.         pPeleFWIMData->pPendingFWIMResponseCommand = nil;
  3289.         status = FWIMCommandIsComplete
  3290.                     (pFWIMAsynchResponseCommandParams->fwimCommandParams.fwimCommandID,
  3291.                      status);
  3292.     }
  3293.  
  3294.     // Return command acceptance.
  3295.     //zzz what if we call FWIMCommandIsComplete before returning this???
  3296.     //zzz well, it still works, but will it always?
  3297.     //zzz actually, when we switch to the dispatch table, each routine can return
  3298.     //zzz the appropriate acceptance, so don't worry about it for now.
  3299.     *pCommandAcceptance = kFWIMCommandAcceptNoMore;
  3300.  
  3301.     return status;
  3302. }
  3303.  
  3304.  
  3305. ////////////////////////////////////////////////////////////////////////////////
  3306. //
  3307. // PeleFWIMWrite
  3308. //
  3309. //   This proc performs a write transaction on the FireWire bus.
  3310. //zzz what if timer goes off before request goes out??? A: Execute this proc
  3311. //zzz at secondary interrupt level
  3312. //zzz check length against maximum packet size
  3313. //zzz should be set up to get acknowledgement
  3314. //
  3315.  
  3316. static OSStatus    PeleFWIMWriteTimer(
  3317.     void                        *p1,
  3318.     void                        *p2)
  3319. {
  3320.     UInt32                        commandAcceptance;
  3321.     OSStatus                    status = noErr;
  3322.  
  3323.     status = PeleFWIMWrite ((FWIMAsynchCommandParamsPtr) p1, &commandAcceptance);
  3324.     return (status);
  3325. }
  3326.  
  3327. static OSStatus    PeleFWIMWrite(
  3328.     FWIMAsynchCommandParamsPtr    pFWIMAsynchCommandParams,
  3329.     UInt32                        *pCommandAcceptance)
  3330. {
  3331.     FWIMCommandParamsPtr        pFWIMCommandParams;
  3332.     PeleFWIMDataPtr                pPeleFWIMData; 
  3333.     OSStatus                    status = noErr;
  3334.     UInt32                        data1, data2, data3, data4;
  3335.  
  3336.     static UInt32 debug = 0;
  3337.  
  3338. //    sprintf (debugStr, "FWIM Write %ld bytes", (long) pFWIMAsynchCommandParams->length);
  3339. //    FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  3340.     
  3341.     // Get our internal data.
  3342.     pFWIMCommandParams = &(pFWIMAsynchCommandParams->fwimCommandParams);
  3343.     pPeleFWIMData = (PeleFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  3344.  
  3345.     // Set pending command.
  3346.     pPeleFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMAsynchCommandParams;
  3347.     pPeleFWIMData->pendingFWIMCommandStatus = kPelePendingFWIMCommandBusy;
  3348.  
  3349.     // Timer is off.
  3350.     pPeleFWIMData->requestTimeoutTimerSet = false;
  3351.  
  3352.     // Check if generation is up to date.
  3353.     if ((!(pPeleFWIMData->generationValid)) ||
  3354.         (pFWIMAsynchCommandParams->generation != pPeleFWIMData->generation))
  3355.     {
  3356.         status = busReconfiguredErr;
  3357.     }
  3358.  
  3359.     //zzz need to set a timeout timer in case we get a ack_pending
  3360.  
  3361.     // Write write request to ATF.
  3362.     if (status == noErr)
  3363.     {
  3364.         if (pFWIMAsynchCommandParams->length == 4)
  3365.         { // Quadlet request.
  3366.             // Write packet control header.
  3367.  
  3368.             pPeleFWIMData->transactionLabel = (pPeleFWIMData->transactionLabel + 1) & 0x3F;
  3369.             pPeleFWIMData->tCode = kFWTCodeWriteQuadlet;
  3370.             data1 = pPeleFWIMData->transactionLabel << kPeleAsynchTLabelPhase;
  3371.             data1 |= kPeleAsynchNew << kPeleAsynchRtPhase;
  3372.             data1 |= kFWTCodeWriteQuadlet << kPelePacketTCodePhase;
  3373.  
  3374.             // Write packet address.
  3375.             data2 = pFWIMAsynchCommandParams->addressHi;
  3376.             data3 = pFWIMAsynchCommandParams->addressLo;
  3377.  
  3378.             // Write packet payload.
  3379.             data4 = (*((UInt32 *) pFWIMAsynchCommandParams->buffer));
  3380.  
  3381.             PeleFWIMWriteAT(pPeleFWIMData, pFWIMAsynchCommandParams->speed, 4, data1, data2, data3, data4, 0, 0);
  3382.         }
  3383.         else
  3384.         { // Block request.
  3385.             // Write packet control header.
  3386.  
  3387.             pPeleFWIMData->transactionLabel = (pPeleFWIMData->transactionLabel + 1) & 0x3F;
  3388.             pPeleFWIMData->tCode = kFWTCodeWriteBlock;
  3389.             data1 = pPeleFWIMData->transactionLabel << kPeleAsynchTLabelPhase;
  3390.             data1 |= kPeleAsynchNew << kPeleAsynchRtPhase;
  3391.             data1 |= kFWTCodeWriteBlock << kPelePacketTCodePhase;
  3392.  
  3393.             // Write packet address.
  3394.             data2 = pFWIMAsynchCommandParams->addressHi;
  3395.             data3 = pFWIMAsynchCommandParams->addressLo;
  3396.  
  3397.             // Write request length.
  3398.             data4 = pFWIMAsynchCommandParams->length << kPeleAsynchDataLengthPhase;
  3399.  
  3400.             PeleFWIMWriteAT (pPeleFWIMData, pFWIMAsynchCommandParams->speed, 4, data1, data2, data3, data4,
  3401.                              pFWIMAsynchCommandParams->length,
  3402.                              (UInt32 *) pFWIMAsynchCommandParams->buffer);
  3403.         }
  3404.     }
  3405.  
  3406.     // Complete command on error.
  3407.     if (status != noErr)
  3408.     {
  3409.         pPeleFWIMData->pPendingFWIMCommand = nil;
  3410.         status = FWIMCommandIsComplete
  3411.                     (pFWIMAsynchCommandParams->fwimCommandParams.fwimCommandID,
  3412.                      status);
  3413.     }
  3414.     else
  3415.     {
  3416.         // We no longer take TxRdy interrupt, instead, the status should already be waiting for us.
  3417.         //zzz We probably should take an interrupt.  Other transmit stuff (like isoch) could
  3418.         //zzz be blocking this transmission for relatively long periods of time.
  3419.         PeleFWIMAckSecondaryInterruptHandler
  3420.             (pPeleFWIMData, &(pPeleFWIMData->asynchXmitDMA[kAsynchTxDataDMA]));
  3421.     }
  3422.  
  3423.     // Return command acceptance.
  3424.     //zzz what if we call FWIMCommandIsComplete before returning this???
  3425.     //zzz well, it still works, but will it always?
  3426.     //zzz actually, when we switch to the dispatch table, each routine can return
  3427.     //zzz the appropriate acceptance, so don't worry about it for now.
  3428.     *pCommandAcceptance = kFWIMCommandAcceptNoMore;
  3429.  
  3430.     return status;
  3431. }
  3432.  
  3433.  
  3434. ////////////////////////////////////////////////////////////////////////////////
  3435. //
  3436. // PeleFWIMWriteResponse
  3437. //
  3438. //   This proc sends a write response packet.
  3439. //zzz should be set up to get acknowledgement
  3440. //
  3441.  
  3442. static OSStatus    PeleFWIMWriteResponse(
  3443.     FWIMAsynchResponseCommandParamsPtr
  3444.                                 pFWIMAsynchResponseCommandParams,
  3445.     UInt32                        *pCommandAcceptance)
  3446. {
  3447.     FWIMCommandParamsPtr        pFWIMCommandParams;
  3448.     PeleFWIMDataPtr                pPeleFWIMData; 
  3449.     UInt32                        data1, data2;
  3450.     UInt32                        transactionLabel;
  3451.     UInt32                        responseCode;
  3452.     OSStatus                    status = noErr;
  3453.  
  3454.     // Get our internal data.
  3455.     pFWIMCommandParams = &(pFWIMAsynchResponseCommandParams->fwimCommandParams);
  3456.     pPeleFWIMData = (PeleFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  3457.  
  3458.     // Set pending command.
  3459.     pPeleFWIMData->pPendingFWIMResponseCommand =
  3460.         (FWIMCommandParamsPtr) pFWIMAsynchResponseCommandParams;
  3461.  
  3462.     // Check if generation is up to date.
  3463.     if ((!(pPeleFWIMData->generationValid)) ||
  3464.         (pFWIMAsynchResponseCommandParams->generation != pPeleFWIMData->generation))
  3465.     {
  3466.         status = busReconfiguredErr;
  3467.     }
  3468.  
  3469.     // Write write response to ATF.
  3470.     if (status == noErr)
  3471.     {
  3472.         // Compute transaction label and response code.
  3473.         transactionLabel = (pFWIMAsynchResponseCommandParams->transactionDescriptor &
  3474.                             kFWTransactionDescriptorTLabel) >>
  3475.                            kFWTransactionDescriptorTLabelPhase;
  3476.         responseCode = (pFWIMAsynchResponseCommandParams->responseDataHi &
  3477.                         kFWResponseDataRCode) >>
  3478.                        kFWResponseDataRCodePhase;
  3479.  
  3480.         // packet control header goes in quad 1
  3481.         data1 = kFWTCodeWriteResponse << kPelePacketTCodePhase;
  3482.         data1 |= transactionLabel << kPeleAsynchTLabelPhase;
  3483.         data1 |= kPeleAsynchNew << kPeleAsynchRtPhase;
  3484.     
  3485.         // packet destination node ID and response code go in quad 2
  3486.         data2 = pFWIMAsynchResponseCommandParams->destinationID << kPeleAsynchSourceIDPhase;
  3487.         data2 |= responseCode << kPeleAsynchRCodePhase;
  3488.  
  3489.         PeleFWIMWriteAT (pPeleFWIMData, pFWIMAsynchResponseCommandParams->speed, 3, data1, data2, 0, 0, 0, 0);
  3490.     }
  3491.  
  3492.     // Complete command on error.
  3493.     //zzz assume success for now.  should check ack code for success.
  3494. //zzz    if (status != noErr)
  3495.     {
  3496.         pPeleFWIMData->pPendingFWIMResponseCommand = nil;
  3497.         status = FWIMCommandIsComplete
  3498.                     (pFWIMAsynchResponseCommandParams->fwimCommandParams.fwimCommandID,
  3499.                      status);
  3500.     }
  3501.  
  3502.     // Return command acceptance.
  3503.     //zzz what if we call FWIMCommandIsComplete before returning this???
  3504.     //zzz well, it still works, but will it always?
  3505.     //zzz actually, when we switch to the dispatch table, each routine can return
  3506.     //zzz the appropriate acceptance, so don't worry about it for now.
  3507.     *pCommandAcceptance = kFWIMCommandAcceptNoMore;
  3508.  
  3509.     return status;
  3510. }
  3511.  
  3512.  
  3513. ////////////////////////////////////////////////////////////////////////////////
  3514. //
  3515. // PeleFWIMLock
  3516. //
  3517. //   This proc performs a lock transaction on the FireWire bus.
  3518. //zzz what if timer goes off before request goes out??? A: Execute this proc
  3519. //zzz at secondary interrupt level
  3520. //zzz check length against maximum packet size
  3521. //zzz should be set up to get acknowledgement
  3522. //
  3523.  
  3524. static OSStatus    PeleFWIMLock(
  3525.     FWIMAsynchCommandParamsPtr    pFWIMAsynchCommandParams,
  3526.     UInt32                        *pCommandAcceptance)
  3527. {
  3528.     FWIMCommandParamsPtr        pFWIMCommandParams;
  3529.     PeleFWIMDataPtr                pPeleFWIMData; 
  3530.     UInt32                        data1, data2, data3, data4;
  3531.     AbsoluteTime                timeoutAbsolute;
  3532.     OSStatus                    status = noErr;
  3533.  
  3534. //    FWDebugStr ((ConstStr255Param) "\pPeleFWIMLock");
  3535.  
  3536.     // Get our internal data.
  3537.     pFWIMCommandParams = &(pFWIMAsynchCommandParams->fwimCommandParams);
  3538.     pPeleFWIMData = (PeleFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  3539.  
  3540.     // Set pending command.
  3541.     pPeleFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMAsynchCommandParams;
  3542.     pPeleFWIMData->pendingFWIMCommandStatus = kPelePendingFWIMCommandBusy;
  3543.  
  3544.     // Check if generation is up to date.
  3545.     if ((!(pPeleFWIMData->generationValid)) ||
  3546.         (pFWIMAsynchCommandParams->generation != pPeleFWIMData->generation))
  3547.     {
  3548.         status = busReconfiguredErr;
  3549.     }
  3550.  
  3551.     // Set a timeout timer.
  3552.     if (status == noErr)
  3553.     {
  3554.         timeoutAbsolute =
  3555.             AddAbsoluteToAbsolute (UpTime (),
  3556.                                    DurationToAbsolute (pFWIMAsynchCommandParams->timeout));
  3557.         status = SetInterruptTimer
  3558.                     (&timeoutAbsolute, PeleFWIMLockRequestTimeoutHandler,
  3559.                      pFWIMAsynchCommandParams,
  3560.                      &(pPeleFWIMData->requestTimeoutTimerID));
  3561.         if (status == noErr)
  3562.             pPeleFWIMData->requestTimeoutTimerSet = true;
  3563.     }
  3564.  
  3565.     // send lock request.
  3566.     if (status == noErr)
  3567.     {
  3568.         pPeleFWIMData->transactionLabel =
  3569.             (pPeleFWIMData->transactionLabel + 1) & 0x3F;
  3570.         pPeleFWIMData->tCode = kFWTCodeLock;
  3571.         
  3572.         // Prepare packet control header for block transaction.
  3573.         data1 = (pPeleFWIMData->transactionLabel << kPeleAsynchTLabelPhase);
  3574.         data1 |= (kPeleAsynchNew << kPeleAsynchRtPhase);
  3575.         data1 |= (kFWTCodeLock << kPelePacketTCodePhase);
  3576.  
  3577.         // our ID and the target address.
  3578.         data2 = pFWIMAsynchCommandParams->addressHi;
  3579.         data3 = pFWIMAsynchCommandParams->addressLo;
  3580.  
  3581.         // request length and extended tCode.
  3582.         data4 = pFWIMAsynchCommandParams->length << kPeleAsynchDataLengthPhase;
  3583.         data4 |= 
  3584.             (pFWIMAsynchCommandParams->extendedTCode & kPeleAsynchExtendedTCode) <<
  3585.             kPeleAsynchExtendedTCodePhase;
  3586.  
  3587.         PeleFWIMWriteAT(pPeleFWIMData, pFWIMAsynchCommandParams->speed, 4, data1, data2, data3, data4,
  3588.                          pFWIMAsynchCommandParams->length,
  3589.                          (UInt32 *) pFWIMAsynchCommandParams->buffer);
  3590.     }
  3591.  
  3592.     // Complete command on error.
  3593.     if (status != noErr)
  3594.     {
  3595.         pPeleFWIMData->pPendingFWIMCommand = nil;
  3596.         status = FWIMCommandIsComplete
  3597.                     (pFWIMAsynchCommandParams->fwimCommandParams.fwimCommandID,
  3598.                      status);
  3599.     }
  3600.  
  3601.     // Return command acceptance.
  3602.     //zzz what if we call FWIMCommandIsComplete before returning this???
  3603.     //zzz well, it still works, but will it always?
  3604.     //zzz actually, when we switch to the dispatch table, each routine can return
  3605.     //zzz the appropriate acceptance, so don't worry about it for now.
  3606.     *pCommandAcceptance = kFWIMCommandAcceptNoMore;
  3607.  
  3608.     return status;
  3609. }
  3610.  
  3611.  
  3612. ////////////////////////////////////////////////////////////////////////////////
  3613. //
  3614. // PeleFWIMLockResponse
  3615. //
  3616. //   This proc sends a lock response packet.
  3617. //zzz should be set up to get acknowledgement
  3618. //
  3619.  
  3620. static OSStatus    PeleFWIMLockResponse(
  3621.     FWIMAsynchResponseCommandParamsPtr
  3622.                                 pFWIMAsynchResponseCommandParams,
  3623.     UInt32                        *pCommandAcceptance)
  3624. {
  3625.     FWIMCommandParamsPtr        pFWIMCommandParams;
  3626.     PeleFWIMDataPtr                pPeleFWIMData; 
  3627.     UInt32                        data1, data2, data4;
  3628.     UInt32                        transactionLabel;
  3629.     UInt32                        responseCode;
  3630.     OSStatus                    status = noErr;
  3631.  
  3632.     // Get our internal data.
  3633.     pFWIMCommandParams = &(pFWIMAsynchResponseCommandParams->fwimCommandParams);
  3634.     pPeleFWIMData = (PeleFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  3635.  
  3636.     // Set pending command.
  3637.     pPeleFWIMData->pPendingFWIMResponseCommand =
  3638.         (FWIMCommandParamsPtr) pFWIMAsynchResponseCommandParams;
  3639.  
  3640.     // Check if generation is up to date.
  3641.     if ((!(pPeleFWIMData->generationValid)) ||
  3642.         (pFWIMAsynchResponseCommandParams->generation != pPeleFWIMData->generation))
  3643.     {
  3644.         status = busReconfiguredErr;
  3645.     }
  3646.  
  3647.     // Write lock response to ATF.
  3648.     if (status == noErr)
  3649.     {
  3650.         // Compute transaction label and response code.
  3651.         transactionLabel = (pFWIMAsynchResponseCommandParams->transactionDescriptor &
  3652.                             kFWTransactionDescriptorTLabel) >>
  3653.                            kFWTransactionDescriptorTLabelPhase;
  3654.         responseCode = (pFWIMAsynchResponseCommandParams->responseDataHi &
  3655.                         kFWResponseDataRCode) >>
  3656.                        kFWResponseDataRCodePhase;
  3657.  
  3658.         // packet control header goes in quad 1
  3659.         data1 = transactionLabel << kPeleAsynchTLabelPhase;
  3660.         data1 |= kPeleAsynchNew << kPeleAsynchRtPhase;
  3661.         data1 |= kFWTCodeLockResponse << kPelePacketTCodePhase;
  3662.  
  3663.         // packet destination node ID and response code go in quad 2
  3664.         data2 = pFWIMAsynchResponseCommandParams->destinationID << kPeleAsynchSourceIDPhase;
  3665.         data2 |= responseCode << kPeleAsynchRCodePhase;
  3666.  
  3667.         data4 = pFWIMAsynchResponseCommandParams->length << kPeleAsynchDataLengthPhase;
  3668.         data4 |= 
  3669.             (pFWIMAsynchResponseCommandParams->extendedTCode & kPeleAsynchExtendedTCode) <<
  3670.             kPeleAsynchExtendedTCodePhase;
  3671.  
  3672.         PeleFWIMWriteAT (pPeleFWIMData, pFWIMAsynchResponseCommandParams->speed, 4, data1, data2, 0, data4, pFWIMAsynchResponseCommandParams->length, (UInt32 *) pFWIMAsynchResponseCommandParams->buffer);
  3673.     }
  3674.  
  3675.     // Complete command on error.
  3676.     //zzz assume success for now.  should check ack code for success.
  3677. //zzz    if (status != noErr)
  3678.     {
  3679.         pPeleFWIMData->pPendingFWIMResponseCommand = nil;
  3680.         status = FWIMCommandIsComplete
  3681.                     (pFWIMAsynchResponseCommandParams->fwimCommandParams.fwimCommandID,
  3682.                      status);
  3683.     }
  3684.  
  3685.     // Return command acceptance.
  3686.     //zzz what if we call FWIMCommandIsComplete before returning this???
  3687.     //zzz well, it still works, but will it always?
  3688.     //zzz actually, when we switch to the dispatch table, each routine can return
  3689.     //zzz the appropriate acceptance, so don't worry about it for now.
  3690.     *pCommandAcceptance = kFWIMCommandAcceptNoMore;
  3691.  
  3692.     return status;
  3693. }
  3694.  
  3695.  
  3696. ////////////////////////////////////////////////////////////////////////////////
  3697. //
  3698. // PeleFWIMIsCompilableDCLProgram
  3699. //
  3700. //   This routine determines if the given DCL program is compilable.
  3701. //zzz a table and range check may be faster.
  3702. //zzz should do better checking.
  3703. //zzz maybe we should make this determination in a first pass compilation.
  3704. //
  3705.  
  3706. static Boolean    PeleFWIMIsCompilableDCLProgram(
  3707.     DCLProgramID                dclProgramID)
  3708. {
  3709.     DCLCommandPtr                pDCLCommand;
  3710.     Boolean                        isCompilable = true;
  3711.     UInt32                        opcode;
  3712.     OSStatus                    status = noErr;
  3713.     
  3714.     FWDebugStr ((ConstStr255Param) "\p PeleFWIMIsCompilableDCLProgram...");
  3715.     
  3716.     // Get first DCL in program.
  3717.     status = FWGetDCLProgramStart (dclProgramID, &pDCLCommand);
  3718.     if (status != noErr)
  3719.         isCompilable = false;
  3720.  
  3721.     // Check each DCL in program.
  3722.     while ((isCompilable) && (pDCLCommand != nil))
  3723.     {
  3724.         opcode = pDCLCommand->opcode;
  3725.         opcode &= ~kFWDCLOpDynamicFlag;  // We can compile dynamic opcodes.
  3726.         switch (opcode)
  3727.         {
  3728.             case kDCLReceivePacketStartOp :
  3729.                 break;
  3730.  
  3731.             case kDCLReceivePacketOp :
  3732.                 break;
  3733.  
  3734.             case kDCLSendPacketStartOp :
  3735.                 break;
  3736.  
  3737.             case kDCLSendPacketWithHeaderStartOp :
  3738.                 break;
  3739.  
  3740.             case kDCLSendPacketOp :
  3741.                 break;
  3742.  
  3743.             case kDCLCallProcOp :
  3744.                 break;
  3745.  
  3746.             case kDCLJumpOp :
  3747.                 break;
  3748.  
  3749.             case kDCLLabelOp :
  3750.                 break;
  3751.  
  3752.             case kDCLSetTagSyncBitsOp :
  3753.                 break;
  3754.  
  3755.             case kDCLUpdateDCLListOp :
  3756.                 break;
  3757.  
  3758.             case kDCLTimeStampOp :
  3759.                 break;
  3760.  
  3761.             default :
  3762.                 isCompilable = false;
  3763.                 break;
  3764.         }
  3765.         
  3766.         pDCLCommand = pDCLCommand->pNextDCLCommand;
  3767.     }
  3768.  
  3769.     sprintf (debugStr, "  isCompilable = %ld", (long) isCompilable);
  3770.     FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  3771.  
  3772.     return isCompilable;
  3773. }
  3774.  
  3775.  
  3776. ////////////////////////////////////////////////////////////////////////////////
  3777. //
  3778. // PeleFWIMPrepareDCLProgramMemory
  3779. //
  3780. //   This routine prepares all buffers used within a DCL program for physical
  3781. //   I/O, and determines the physical addresses.  dclList is the entire program.
  3782. //
  3783.  
  3784. static OSStatus PeleFWIMPrepareDCLProgramMemory(
  3785.     PeleDCLCompilerEngineDataPtr
  3786.                                 pPeleDCLCompilerEngineData,
  3787.     DCLCommandPtr                dclList,
  3788.     UInt32                        dclListLength)
  3789. {
  3790.     DCLCommandPtr                pDCL;
  3791.     DCLTransferPacketPtr        pDCLTransferPacket;
  3792.     IOPreparationTable            *ioPrep;
  3793.     PhysicalAddress                *physAddrs;                // should be PhysicalMappingTablePtr
  3794.     AddressRangeTablePtr        rangeTable;
  3795.     UInt32                        pageSize, pageShift, pageMask, tmp;
  3796.     UInt32                        pageCount, bufferCount;
  3797.     AbsoluteTime                timeNow;
  3798.     OSStatus                    status = noErr;
  3799.     
  3800.     FWDebugStr ((ConstStr255Param) "\p PeleFWIMPrepareDCLProgramMemory");
  3801.     
  3802.     ioPrep = &pPeleDCLCompilerEngineData->ioPrep;
  3803.     pageSize = GetLogicalPageSize ();
  3804.     pageShift = 0;
  3805.     for (tmp = pageSize; tmp = tmp >> 1; pageShift++);            // Sorry...
  3806.     pageMask = ~(pageSize - 1);
  3807.     
  3808.     // This is gross too.  Make sure we don't use stale data in lookups.
  3809.     timeNow = UpTime ();
  3810.     pPeleDCLCompilerEngineData->engineGeneration = AbsoluteToDuration (timeNow);
  3811.     
  3812.     // We will need to allocate a page table.  We don't know how big it needs
  3813.     // to be, but we can wait until just before we PrepareMemoryForIO to do
  3814.     // the allocation (by then we'll know)
  3815.     
  3816.     // We need to allocate a range/length table.  We fill that in before we
  3817.     // call PrepareMemoryForIO, and it has to be linear, so we have to allocate
  3818.     // it all at once.  We need one entry for each buffer in the program.
  3819.     // That's why we take a parameter indicating the program length.
  3820.     // Note if we ever allow scatter/gather buffers in a DCL program, this
  3821.     // will have to change.
  3822.     
  3823.     // We assumed (in PeleFWIMCompileDCLProgram) that each DCL contained a buffer.
  3824.     // Some of them are branches, etc, so an optimization would be to count more
  3825.     // precisely and save a little memory.
  3826.     
  3827.     // Allocate space for rangeTable
  3828.     if (status == noErr)
  3829.     {        
  3830.         rangeTable = (AddressRangeTablePtr)
  3831.             PoolAllocateResident (dclListLength * sizeof (AddressRange), false);
  3832.         if (!rangeTable) status = memFullErr;
  3833.         ioPrep->rangeInfo.multipleRanges.entryCount = 0;
  3834.         // move this below, use local copy
  3835.         ioPrep->rangeInfo.multipleRanges.rangeTable = rangeTable;
  3836.     }    
  3837.  
  3838.     // Gather information about buffers/pointers
  3839.     if (status == noErr)
  3840.     {
  3841.         pDCL = dclList;
  3842.         bufferCount = 0;        // shadow of ioPrep->rangeInfo.multipleRanges.entryCount
  3843.         pageCount = 0;            // count page table size we will need to allocate
  3844.         
  3845.         while (pDCL != nil)
  3846.         {
  3847.             switch (pDCL->opcode & ~kFWDCLOpFlagMask)
  3848.             {
  3849.                 case kDCLReceivePacketStartOp :
  3850.                 case kDCLReceivePacketOp :
  3851.                 case kDCLSendPacketStartOp :
  3852.                 case kDCLSendPacketWithHeaderStartOp :
  3853.                 case kDCLSendPacketOp :
  3854.  
  3855.                     pDCLTransferPacket = (DCLTransferPacketPtr) pDCL;
  3856.                     rangeTable[bufferCount].base = (void *) pDCLTransferPacket->buffer;
  3857.                     rangeTable[bufferCount].length = pDCLTransferPacket->size;
  3858.                     bufferCount++;
  3859.                     
  3860.                     // buffer + size - 1 is addr of last byte in buffer.
  3861.                     // shift that right by pageShift to get page index of end.
  3862.                     // subtract first page index and add one to get total page count.
  3863.                     
  3864.                     pageCount += // (last page - first page) + 1
  3865.                         ((((((UInt32) (pDCLTransferPacket->buffer)) + pDCLTransferPacket->size) - 1) >> pageShift) -
  3866.                             (((UInt32) (pDCLTransferPacket->buffer)) >> pageShift) + 1);
  3867.                     break;
  3868.                     
  3869.                 default : //No buffer or pointer - nothing to do
  3870.                     break;
  3871.             }
  3872.  
  3873.             pDCL = pDCL->pNextDCLCommand;
  3874.         }
  3875.     }
  3876.  
  3877.     // Allocate space for page table
  3878.     if (status == noErr)
  3879.     {
  3880.         physAddrs = PoolAllocateResident (pageCount * sizeof (PhysicalAddress), false);
  3881.         if (!physAddrs)
  3882.         {
  3883.             status = memFullErr;
  3884.             PoolDeallocate ((Ptr) rangeTable);
  3885.         }
  3886.         pPeleDCLCompilerEngineData->physAddrs = physAddrs;
  3887.     }
  3888.     
  3889.     // Prepare memory for I/O
  3890.     if (status == noErr)
  3891.     {
  3892.         ioPrep->options = kIOMultipleRanges | kIOLogicalRanges |
  3893.                           kIOIsInput | kIOIsOutput;
  3894.         ioPrep->addressSpace = kCurrentAddressSpaceID;            // default
  3895.         ioPrep->granularity = 0;                                // do it all now
  3896.         ioPrep->firstPrepared = 0;
  3897.         ioPrep->mappingEntryCount = pageCount;                    // we counted exactly
  3898.         ioPrep->logicalMapping = 0;
  3899.         ioPrep->physicalMapping = physAddrs;                    // return list of phys addrs
  3900.         ioPrep->rangeInfo.multipleRanges.entryCount = bufferCount;
  3901.  
  3902.         // CheckpointIO is in _PeleFWIMReleaseIsochPort
  3903.         status = PrepareMemoryForIO (ioPrep);
  3904.         if (status != noErr)
  3905.         {
  3906.             ioPrep->mappingEntryCount = -1;                        // prevents CheckpointIO, kind of a hack
  3907.             PoolDeallocate ((Ptr) rangeTable);
  3908.             PoolDeallocate ((Ptr) physAddrs);
  3909.  
  3910.             sprintf (debugStr, "DCL data PrepMemIO status %ld    page count %ld",
  3911.                      (long) status,
  3912.                      (long) pageCount);
  3913.             FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  3914.         }
  3915.     }
  3916.     
  3917.     return status;
  3918. }
  3919.  
  3920.  
  3921. ////////////////////////////////////////////////////////////////////////////////
  3922. //
  3923. // PeleFWIMDataMapBufferToPhysical
  3924. //
  3925. //   This routine looks up physical addresses for buffers/pointers.
  3926. //     Fills in the passed page table, returns page count (0 if not found)
  3927.  
  3928. static UInt32 PeleFWIMDataMapToPhysical (
  3929.     PeleDCLCompilerEngineDataPtr
  3930.                                 pPeleDCLCompilerEngineData,
  3931.     Ptr                            pBuffer,
  3932.     UInt32                        size,
  3933.     PhysicalMappingTablePtr        returnTable)
  3934. {
  3935.     UInt32                        pageCount = 0, lookCount = 0;
  3936.     static UInt32                rangeLook = 0, pageLook = 0;
  3937.     static UInt32                pageSize = 0, pageShift = 0;
  3938.     static UInt32                cacheEngineGeneration = 0;
  3939.     IOPreparationTable            *ioPrep = &pPeleDCLCompilerEngineData->ioPrep;
  3940.     AddressRangeTablePtr        try;
  3941.     if (!pageSize)
  3942.     {
  3943.         UInt32 tmp;
  3944.         pageSize = GetLogicalPageSize ();
  3945.         for (tmp = pageSize; tmp = tmp >> 1; pageShift++);            // Sorry...
  3946.     }
  3947.     
  3948.     // Look up phys addrs in our prepared table
  3949.     // Return in provided page table
  3950.     
  3951.     // Start lookup from last known point, if we build in order, lookup is fast
  3952.     // Strictly speaking, rangeLook and pageLook should be static to the
  3953.     // engine data, not the whole FWIM, but I don't think we can compile more
  3954.     // than one DCL program at a time anyway.
  3955.     //
  3956.     // Perhaps more importantly, they should be reset if we've rebuilt the ioPrep,
  3957.     // because they may be off the end or otherwise inaccurate.
  3958.     //
  3959.     // I'm not sure this (optimization) works - it still seems sluggish.
  3960.     
  3961.     if (cacheEngineGeneration != pPeleDCLCompilerEngineData->engineGeneration)
  3962.     {
  3963.         cacheEngineGeneration = pPeleDCLCompilerEngineData->engineGeneration;
  3964.         rangeLook = 0;
  3965.         pageLook = 0;
  3966.     }
  3967.     
  3968.     // Repeat until we find it or run out of places to look
  3969.     
  3970.     while ((lookCount < ioPrep->rangeInfo.multipleRanges.entryCount) && (!pageCount))
  3971.     {
  3972.         try = &ioPrep->rangeInfo.multipleRanges.rangeTable[rangeLook];
  3973.         
  3974.         // pageCount is number of physAddr entries used by this range
  3975.         // either copy them (found) or skip over them (not found)
  3976.         
  3977.         pageCount = 1 + (((UInt32) try->base + try->length - 1) >> pageShift) -
  3978.                          ((UInt32) try->base >> pageShift);
  3979.                          
  3980.         // require exact match
  3981.         if ((void *) pBuffer == ioPrep->rangeInfo.multipleRanges.rangeTable[rangeLook].base)
  3982.         {
  3983.             // Found pages we want.  Copy page table.
  3984.             BlockCopy (&ioPrep->physicalMapping[pageLook],
  3985.                        returnTable,
  3986.                        pageCount * sizeof (PhysicalAddress));
  3987.             pageLook += pageCount;
  3988.         }
  3989.         else
  3990.         {
  3991.             // These aren't the pages we're looking for.  Skip forward.
  3992.             pageLook += pageCount;
  3993.             pageCount = 0;
  3994.         }
  3995.         
  3996.         lookCount++;
  3997.         rangeLook++;
  3998.         if (rangeLook == ioPrep->rangeInfo.multipleRanges.entryCount)
  3999.         {
  4000.             rangeLook = 0;
  4001.             pageLook = 0;
  4002.         }
  4003.     }
  4004.     
  4005.     if (!pageCount)
  4006.         FWDebugStr ((ConstStr255Param) "\pFailed to find buffer!");
  4007.     
  4008.     return pageCount;
  4009. }
  4010.  
  4011.  
  4012. ////////////////////////////////////////////////////////////////////////////////
  4013. //
  4014. // PeleFWIMCompileDCLProgram
  4015. //
  4016. //   This routine compiles the given DCL program into a PCL program.
  4017. //zzz rename this
  4018. //zzz need to set proper speed.
  4019. //
  4020.  
  4021. static OSStatus PeleFWIMCompileDCLProgram(
  4022.     PeleFWIMDataPtr                pPeleFWIMData,
  4023.     DCLProgramID                dclProgramID,
  4024.     UInt32                        dmaChannelNum,
  4025.     UInt32                        channelNum,
  4026.     UInt32                        speed)
  4027. {
  4028.     PeleDMABuildStatePtr        pPeleDMABuildState = nil;
  4029.     PeleDCLCompilerEngineDataPtr
  4030.                                 pPeleDCLCompilerEngineData = nil;
  4031.     DCLCommandPtr                pDCLCommand,
  4032.                                 dclList;
  4033. //    DCLLabel                    waitLoopDCLLabel,
  4034. //                                transmitDCLLabel;
  4035. //    DCLCommand                    waitLoopDCLCommand;
  4036.     PeleDMAPtr                    pStartDMA;
  4037.     UInt32                        startEvent,
  4038.                                 startEventState,
  4039.                                 startEventStateMask;
  4040.     UInt32                        dclListLength;
  4041.     PeleDCLCompilerDCLDataPtr    pPeleDCLCompilerDCLData;
  4042.     OSStatus                    status = noErr;
  4043.  
  4044.     FWDebugStr ((ConstStr255Param) "\p PeleFWIMCompileDCLProgram");
  4045.     
  4046.     // Create DCL engine data record.
  4047.     pPeleDCLCompilerEngineData = (PeleDCLCompilerEngineDataPtr)
  4048.         PoolAllocateResident (sizeof (PeleDCLCompilerEngineData), true);
  4049.     if (pPeleDCLCompilerEngineData == nil)
  4050.         status = memFullErr;
  4051.  
  4052.     // Initialize interrupt queue.
  4053.     if (status == noErr)
  4054.         pPeleFWIMData->pDCLInterruptTail[dmaChannelNum] = nil;
  4055.         
  4056.     // Set compiler notification proc.
  4057.     if (status == noErr)
  4058.     {
  4059.         status = FWSetDCLProgramCompilerNotificationProc
  4060.                     (dclProgramID, PeleFWIMDCLCompilerNotification);
  4061.     }
  4062.  
  4063.     // Get DCL list from program.
  4064.     //zzz should check for error.
  4065.     if (status == noErr)
  4066.         status = FWGetDCLProgramStart (dclProgramID, &dclList);
  4067.  
  4068.     // Count DCLs.
  4069.     if (status == noErr)
  4070.     {
  4071.         pDCLCommand = dclList;
  4072.         dclListLength = 0;
  4073.         while (pDCLCommand != nil)
  4074.         {
  4075.             pDCLCommand = pDCLCommand->pNextDCLCommand;
  4076.             dclListLength++;
  4077.         }
  4078.     }
  4079.     
  4080.     // Allocate compiler data structures for all DCLs
  4081.     if (status == noErr)
  4082.     {
  4083.         pPeleDCLCompilerDCLData =
  4084.             PoolAllocateResident (dclListLength * sizeof (PeleDCLCompilerDCLData), true);
  4085.         if (pPeleDCLCompilerDCLData == nil)
  4086.         {
  4087.             status = memFullErr;
  4088.         }
  4089.         else
  4090.         {
  4091.             pPeleDCLCompilerEngineData->pPeleDCLCompilerDCLData = pPeleDCLCompilerDCLData;
  4092.             // Assign compiler data storage to each DCL
  4093.             pDCLCommand = dclList;
  4094.             while (pDCLCommand != nil)
  4095.             {
  4096.                 pDCLCommand->compilerData = (UInt32) pPeleDCLCompilerDCLData;
  4097.                 pDCLCommand = pDCLCommand->pNextDCLCommand;
  4098.                 pPeleDCLCompilerDCLData++;
  4099.             }
  4100.         }
  4101.     }
  4102.  
  4103.     // The plan is to, before compiling, scan the program to locate all data
  4104.     // buffers.  Then we'll prepare VM mappings for them all at once.  Then
  4105.     // during compilation we can look up the logical->physical mappings.
  4106.     //
  4107.     // A complication is that we may receive notification that a running
  4108.     // program has had its buffers changed.  We get a list of changes.  In
  4109.     // that case we need to prepare the new buffers for DMA and change the
  4110.     // pointers in the PCLs, possibly expanding PCLs if there are more
  4111.     // page crossings than before.  (or maybe not)
  4112.     //
  4113.     // When we update buffers, some may be unchanged, so we can't clear the
  4114.     // original PrepareMemoryForIO.  Buffers can be updated repeatedly, and
  4115.     // we could pile up unlimited ioPrep structures.  So we use a brute-force
  4116.     // solution (NYI) and redo the *entire* ioPrep, not just the changed buffers.
  4117.     // Then we can free (CheckpointIO) the original one, and all live buffers
  4118.     // are still covered.  (There is room for optimizations in that process.)
  4119.     //
  4120.     // The first time we prepare memory, we have the luxury that the program
  4121.     // is not running.  When we do updates, the program *is* running.  But maybe
  4122.     // we can use the same code both times, somehow.
  4123.     
  4124.     if (status == noErr)
  4125.         status = PeleFWIMPrepareDCLProgramMemory (pPeleDCLCompilerEngineData,
  4126.                                                   dclList,
  4127.                                                   dclListLength);
  4128.  
  4129.     // Start writing our DBDMA program.
  4130.     if (status == noErr)
  4131.     {
  4132.         status = PeleFWIMDMAStart (pPeleFWIMData, &pPeleDMABuildState, &pStartDMA);
  4133.         
  4134.         if (status == noErr)
  4135.         {
  4136.             pPeleDMABuildState->pPeleDCLCompilerEngineData = pPeleDCLCompilerEngineData;
  4137.             pPeleDMABuildState->dmaChannelNum = dmaChannelNum;
  4138.             pPeleDMABuildState->isochChannelNum = channelNum;
  4139.         }
  4140.     }
  4141.     
  4142.     // Check if there's a start event for the cycle count.
  4143.     if (status == noErr)
  4144.     {
  4145.         status = FWGetDCLProgramStartEvent
  4146.                     (dclProgramID, &startEvent, &startEventState, &startEventStateMask);
  4147.     }
  4148.     if ((status == noErr) && (startEvent == kFWDCLCycleEvent))
  4149.     {//zzz need to deal with mask including upper 16 bits
  4150.     
  4151. // This is all Lynx based.  Replace with Pele start-on-cycle hardware mechanism
  4152. // In Lynx, we match on bits 12-15 (low 4 of cycle number).  But Pele always matches
  4153. // all 20 bits of cycle number + cycle second.
  4154. #if 0
  4155.         // Create some DCLs to wait for cycle event.
  4156.         waitLoopDCLLabel.pNextDCLCommand = &waitLoopDCLCommand;
  4157.         waitLoopDCLLabel.compilerData = nil;
  4158.         waitLoopDCLLabel.opcode = kDCLLabelOp;
  4159.     
  4160.         waitLoopDCLCommand.pNextDCLCommand = (DCLCommandPtr) &transmitDCLLabel;
  4161.         waitLoopDCLCommand.compilerData = nil;
  4162.         waitLoopDCLCommand.opcode = kDCLInvalidOp;
  4163.  
  4164.         transmitDCLLabel.pNextDCLCommand = dclList;
  4165.         transmitDCLLabel.compilerData = nil;
  4166.         transmitDCLLabel.opcode = kDCLLabelOp;
  4167.  
  4168.         // Add wait loop label.
  4169.         status = 
  4170.             PeleFWIMAddLabelDCL (pPeleDMABuildState, (DCLCommandPtr) &waitLoopDCLLabel);
  4171.  
  4172.         // Add a wait for cycle count commands.
  4173.         // We must set up to start filling the cycle before the cycle we want the packet
  4174.         // to go out on.
  4175.         //zzz setting a compare for startEventState - (1 << 12) will only work right
  4176.         //zzz when bit 12 is set in the mask.
  4177.         if (status == noErr)
  4178.         {
  4179.             //This address is already physical, no translation needed
  4180.             status =
  4181.                 PeleFWIMPCLLoadTemp (pPeleDMABuildState,
  4182.                                      (Ptr) &(pPeleFWIMData->pPeleRegisters->cycleTimer));
  4183.         }
  4184.         if (status == noErr)
  4185.         {
  4186.             status = PeleFWIMPCLCompareTemp16WithMask (pPeleDMABuildState,
  4187.                                                        startEventState - (1 << 12),
  4188.                                                        startEventStateMask);
  4189.         }
  4190.         if (status == noErr)
  4191.             status = PeleFWIMPCLBranchIfEqual (pPeleDMABuildState, &transmitDCLLabel);
  4192.         if (status == noErr)
  4193.             status = PeleFWIMPCLJump (pPeleDMABuildState, &waitLoopDCLLabel, nil);
  4194.  
  4195.         // Add transmit label.
  4196.         if (status == noErr)
  4197.         {
  4198.             status = PeleFWIMAddLabelDCL (pPeleDMABuildState,
  4199.                                           (DCLCommandPtr) &transmitDCLLabel);
  4200.             
  4201.             // Set ready register to 1 after we exit the wait loop.
  4202.             // We'll stop transmitting if we find ready has been zeroed.
  4203.             
  4204.             status = PeleFWIMPCLStore1 (pPeleDMABuildState,
  4205.                      (Ptr) &(pPeleFWIMData->pPeleRegisters->dmaChannel[kIsochTransmitDMA].ready));
  4206.         }
  4207. #endif
  4208.     }
  4209.  
  4210.     // Process all DCLs.
  4211.     pDCLCommand = dclList;
  4212.     while ((pDCLCommand != nil) && (status == noErr))
  4213.     {
  4214.         status = PeleFWIMAddDCL (pPeleDMABuildState, pDCLCommand);
  4215.         pDCLCommand = pDCLCommand->pNextDCLCommand;
  4216.     }
  4217.  
  4218.     if (status == noErr)
  4219.         status = PeleFWIMAddStopDCL (pPeleDMABuildState);
  4220.  
  4221.     // Fill in DCL engine data record.
  4222.     if (status == noErr)
  4223.     {
  4224.         pPeleDCLCompilerEngineData->pStartDMA = pStartDMA;
  4225.         pPeleDCLCompilerEngineData->pPeleDMAPoolDataList =
  4226.             pPeleDMABuildState->pPeleDMAPoolDataList;
  4227.         pPeleDCLCompilerEngineData->pPeleFWIMData = pPeleFWIMData;
  4228.     }
  4229.     
  4230.     // Save engine data.
  4231.     if (status == noErr)
  4232.     {
  4233.         status = FWSetDCLProgramEngineData (dclProgramID,
  4234.                                             (UInt32) pPeleDCLCompilerEngineData);
  4235.     }
  4236.     
  4237.     // Clean up on error.
  4238.     if (status != noErr)
  4239.     {
  4240.         // Deallocate PCL pools.
  4241.         if (pPeleDMABuildState != nil)
  4242.             if (pPeleDMABuildState->pPeleDMAPoolDataList != nil)
  4243.                 PeleFWIMDeallocateDMAPools (pPeleDMABuildState->pPeleDMAPoolDataList);
  4244.  
  4245.         // Deallocate compiler DCL data.
  4246.         if (pPeleDCLCompilerEngineData != nil)
  4247.             if (pPeleDCLCompilerEngineData->pPeleDCLCompilerDCLData != nil)
  4248.                 PoolDeallocate ((Ptr) pPeleDCLCompilerEngineData->pPeleDCLCompilerDCLData);
  4249.  
  4250.         // Deallocate engine data.
  4251.         if (pPeleDCLCompilerEngineData != nil)
  4252.             PoolDeallocate ((Ptr) pPeleDCLCompilerEngineData);
  4253.     }
  4254.  
  4255.     // Clean up.
  4256.     if (pPeleDMABuildState != nil)
  4257.         PoolDeallocate ((Ptr) pPeleDMABuildState);
  4258.  
  4259.     sprintf (debugStr, "   ...PeleFWIMCompileDCLProgram returns %ld", (long) status);
  4260.     FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  4261.  
  4262.     return status;
  4263. }
  4264.  
  4265.  
  4266. ////////////////////////////////////////////////////////////////////////////////
  4267. //
  4268. // PeleFWIMAddDCL
  4269. //
  4270. //   This proc adds the given DCL.
  4271. //
  4272.  
  4273. static OSStatus PeleFWIMAddDCL(
  4274.     PeleDMABuildStatePtr        pPeleDMABuildState,
  4275.     DCLCommandPtr                pDCLCommand)
  4276. {
  4277.     UInt32                        opcode;
  4278.     OSStatus                    status = noErr;
  4279.  
  4280.     // Dispatch off of opcode.
  4281.     opcode = pDCLCommand->opcode & ~kFWDCLOpFlagMask;
  4282.  
  4283. //    sprintf (debugStr, "PeleFWIMAddDCL %ld / %ld", (long) opcode, (long) pDCLCommand->opcode);
  4284. //    FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  4285.  
  4286.     switch (opcode)
  4287.     {
  4288.         case kDCLReceivePacketStartOp :
  4289.             status = PeleFWIMAddReceivePacketStartDCL (pPeleDMABuildState, pDCLCommand);
  4290.             break;
  4291.             
  4292.         case kDCLReceivePacketOp :
  4293.             status = PeleFWIMAddReceivePacketDCL (pPeleDMABuildState, pDCLCommand);
  4294.             break;
  4295.             
  4296.         case kDCLSendPacketStartOp :
  4297.             status = PeleFWIMAddSendPacketStartDCL (pPeleDMABuildState, pDCLCommand);
  4298.             break;
  4299.             
  4300.         case kDCLSendPacketWithHeaderStartOp :
  4301.             status = PeleFWIMAddSendPacketWithHeaderStartDCL (pPeleDMABuildState, pDCLCommand);
  4302.             break;
  4303.             
  4304.         case kDCLSendPacketOp :
  4305.             status = PeleFWIMAddSendPacketDCL (pPeleDMABuildState, pDCLCommand);
  4306.             break;
  4307.  
  4308.         case kDCLCallProcOp :
  4309.             status = PeleFWIMAddCallProcDCL (pPeleDMABuildState, pDCLCommand);
  4310.             break;
  4311.  
  4312.         case kDCLJumpOp :
  4313.             status = PeleFWIMAddJumpDCL (pPeleDMABuildState, pDCLCommand);
  4314.             break;
  4315.  
  4316.         case kDCLLabelOp :
  4317.             status = PeleFWIMAddLabelDCL (pPeleDMABuildState, pDCLCommand);
  4318.             break;
  4319.  
  4320.         case kDCLSetTagSyncBitsOp :
  4321.             status = PeleFWIMAddSetTagSyncBitsDCL (pPeleDMABuildState, pDCLCommand);
  4322.             break;
  4323.  
  4324.         case kDCLUpdateDCLListOp :
  4325.             status = PeleFWIMAddUpdateDCLListDCL (pPeleDMABuildState, pDCLCommand);
  4326.             break;
  4327.  
  4328.         case kDCLTimeStampOp :
  4329.             status = PeleFWIMAddTimeStampDCL (pPeleDMABuildState, pDCLCommand);
  4330.             break;
  4331.  
  4332.         default : //zzz what can we do?
  4333.             break;
  4334.     }
  4335.     
  4336.     return status;
  4337. }
  4338.  
  4339.  
  4340. ////////////////////////////////////////////////////////////////////////////////
  4341. //
  4342. // PeleFWIMAddReceivePacketStartDCL
  4343. //
  4344. //   This proc adds a receive packet start DCL.
  4345. //zzz need to be able to specify speed.
  4346. //
  4347.  
  4348. static OSStatus PeleFWIMAddReceivePacketStartDCL(
  4349.     PeleDMABuildStatePtr        pPeleDMABuildState,
  4350.     DCLCommandPtr                pDCLCommand)
  4351. {
  4352.     DCLTransferPacketPtr        pDCLTransferPacket;
  4353.     PeleDCLCompilerDCLDataPtr    pPeleDCLCompilerDCLData;
  4354.     PeleDMAPtr                    pDMA;
  4355.     PhysicalAddress                pDMAPhys;
  4356.     PhysicalAddress                physAddrs[4];        // enough for 800 mbits
  4357.     UInt32                        pageCount;
  4358.     OSStatus                    status = noErr;
  4359.  
  4360.     // Recast DCL command.
  4361.     pDCLTransferPacket = (DCLTransferPacketPtr) pDCLCommand;
  4362.     pPeleDCLCompilerDCLData = (PeleDCLCompilerDCLDataPtr) pDCLTransferPacket->compilerData;
  4363.     
  4364.     // Allocate new descriptor.
  4365.     status = PeleFWIMAllocateDMA (pPeleDMABuildState, &pDMA, &pDMAPhys, 1);
  4366.     
  4367.     // Get physical addresses.
  4368.     pageCount = PeleFWIMDataMapToPhysical (pPeleDMABuildState->pPeleDCLCompilerEngineData,
  4369.                                            pDCLTransferPacket->buffer,
  4370.                                            pDCLTransferPacket->size,
  4371.                                            physAddrs);
  4372.  
  4373.     // For now, pageCount can be at most 2.  3 pages would be 4098 bytes, not possible at 200mbps.
  4374.     // We can handle 2 only if contiguous.
  4375.     if (pageCount == 2)
  4376.     {
  4377.         // Hack - know page size is 4096 (2^^12)
  4378.         if ((((UInt32) (physAddrs[0])) >> 12) + 1 != (((UInt32) (physAddrs[1])) >> 12))
  4379.         {
  4380.             sprintf (debugStr, "Isoch receive spans 2 pages, not contig [%08lx & %08lx]",
  4381.                      (long) physAddrs[0],
  4382.                      (long) physAddrs[1]);
  4383.             FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  4384.             status = -1;
  4385.         }
  4386.     }
  4387.     
  4388.     // Set up descriptor.
  4389.     if (status == noErr)
  4390.     {
  4391.         // Unlike Lynx, Pele does not receive the 1394 isoch packet header.  It gets
  4392.         // stripped out in hardware.  But the API requires it to be put in the target
  4393.         // buffer.  So, push the buffer forward 4 bytes, and we'll fake the header later
  4394.         // during the update.
  4395.         
  4396.         pDMA->operation =
  4397.             EndianSwap32Bit (kPeleINPUT_LAST |                    // Entire packet in one buffer
  4398.                              kPeleKEY_STREAM0 |                    // Only STREAM implemented
  4399.                              kPeleIntNever |                    // No Interrupt
  4400.                              kPeleBranchAlways |                // Branch to next descriptor
  4401.                              kPeleWaitNever |                    // No wait
  4402.                              (pDCLTransferPacket->size - 4));    // reqCount
  4403.         pDMA->address = EndianSwap32Bit (((UInt32) physAddrs[0]) + 4);
  4404.         pDMA->cmdDep = EndianSwapImm32Bit (0);        // branch address - will be filled in later.
  4405.         pDMA->result = EndianSwapImm32Bit (0);        // modified when DMA complete
  4406.     }
  4407.     
  4408.     // Link previous descriptor.
  4409.     if ((status == noErr) && pPeleDMABuildState->pLastBranch)
  4410.     {
  4411.         *(pPeleDMABuildState->pLastBranch) = EndianSwap32Bit ((UInt32) pDMAPhys);
  4412.     }
  4413.  
  4414.     // Update build state.
  4415.     if (status == noErr)
  4416.     {
  4417.         // Our new descriptor doesn't yet have a branch address.  Here's where it goes:
  4418.         pPeleDMABuildState->pLastBranch = (UInt32 *) &(pDMA->cmdDep);
  4419.     }
  4420.     
  4421.     // Return results.
  4422.     if (status == noErr)
  4423.     {
  4424.         pPeleDCLCompilerDCLData->pDMA = pDMA;
  4425.         pPeleDCLCompilerDCLData->pDMAPhys = pDMAPhys;
  4426.     }
  4427.     else
  4428.     {
  4429.         pPeleDCLCompilerDCLData->pDMA = nil;
  4430.         pPeleDCLCompilerDCLData->pDMAPhys = nil;
  4431.     }
  4432.  
  4433.     return status;
  4434. }
  4435.  
  4436.  
  4437. ////////////////////////////////////////////////////////////////////////////////
  4438. //
  4439. // PeleFWIMAddReceivePacketDCL
  4440. //
  4441. //   This proc adds a receive packet DCL.
  4442. //
  4443.  
  4444. static OSStatus PeleFWIMAddReceivePacketDCL(
  4445.     PeleDMABuildStatePtr        pPeleDMABuildState,
  4446.     DCLCommandPtr                pDCLCommand)
  4447. {
  4448.     FWDebugStr ((ConstStr255Param) "\pPeleFWIMAddReceivePacketDCL is not supported");
  4449.     return -1;
  4450. #if 0
  4451.     DCLTransferPacketPtr        pDCLTransferPacket;
  4452.     PeleDCLCompilerDCLDataPtr    pPeleDCLCompilerDCLData;
  4453.     OSStatus                    status = noErr;
  4454.  
  4455. There is just no good general-purpose way to compile this opcode if the packet
  4456. sizes are unpredictable and the buffers sent to us are not contiguous, because
  4457. Pele can't deal with that.  At best, we could check for contiguous buffers and
  4458. merge them, issuing a paramErr otherwise.  The only other way out is to allocate
  4459. our own big buffer in the FWIM and then copy out the results during the Update.
  4460. That uses a lot of memory and CPU and seems kind of pointless.
  4461.  
  4462.     // Recast DCL command.
  4463.     pDCLTransferPacket = (DCLTransferPacketPtr) pDCLCommand;
  4464.     pPeleDCLCompilerDCLData = (PeleDCLCompilerDCLDataPtr) pDCLTransferPacket->compilerData;
  4465.     
  4466.     return status;
  4467. #endif
  4468. }
  4469.  
  4470.  
  4471. ////////////////////////////////////////////////////////////////////////////////
  4472. //
  4473. // PeleFWIMAddSendPacketStartDCL
  4474. //
  4475. //   This proc adds a send packet start DCL.
  4476. //   It also compiles the following sendPacketOp DCLs
  4477. //zzz need to be able to specify speed.
  4478. //
  4479.  
  4480. static OSStatus PeleFWIMAddSendPacketStartDCL(
  4481.     PeleDMABuildStatePtr        pPeleDMABuildState,
  4482.     DCLCommandPtr                pDCLCommand)
  4483. {
  4484.     DCLTransferPacketPtr        pDCLTransferPacket,
  4485.                                 pDCLTransferPacketStart;
  4486.     PeleDCLCompilerDCLDataPtr    pPeleDCLCompilerDCLData;
  4487.     UInt32                        packetSize, packetPageCount, doPage;
  4488.     PhysicalAddress                physTable[20];        // what is a realistic limit?
  4489.     UInt32                        sizeTable[20];        // ???
  4490.     UInt32                        pageCount;//, pageSize, firstPageSize;
  4491.     PeleDMAPtr                    pDMA, pDoDMA;
  4492.     PhysicalAddress                pDMAPhys;
  4493.     OSStatus                    status = noErr;
  4494.  
  4495.     // Recast DCL command.
  4496.     pDCLTransferPacketStart = (DCLTransferPacketPtr) pDCLCommand;
  4497.     pPeleDCLCompilerDCLData = (PeleDCLCompilerDCLDataPtr) pDCLTransferPacket->compilerData;
  4498.  
  4499.     // First scan any SendPacketOp DCLs that follow this SendPacketStartOp DCL.
  4500.     // They will all combine with this one to send a single packet.  Find out
  4501.     // all of the physical addresses and data sizes that we will need, including
  4502.     // a count of descriptors.
  4503.         
  4504.     pDCLTransferPacket = pDCLTransferPacketStart;
  4505.     packetSize = 0;
  4506.     packetPageCount = 0;
  4507.     do
  4508.     {
  4509.         packetSize += pDCLTransferPacket->size;
  4510.         pageCount = PeleFWIMDataMapToPhysical (pPeleDMABuildState->pPeleDCLCompilerEngineData,
  4511.                                                pDCLTransferPacket->buffer,
  4512.                                                pDCLTransferPacket->size,
  4513.                                                &(physTable[packetPageCount]));
  4514.         
  4515.         if (pageCount == 1)
  4516.         {
  4517.             sizeTable[packetPageCount] = pDCLTransferPacket->size;
  4518.         }
  4519.         else if (pageCount == 2)
  4520.         {
  4521.             // Page size hardwired to 4096 / 0x1000 for now
  4522.             sizeTable[packetPageCount] = 0x1000 - ((UInt32) physTable[packetPageCount] & 0x0fff);
  4523.             sizeTable[packetPageCount + 1] = pDCLTransferPacket->size - sizeTable[packetPageCount];
  4524.         }
  4525.         else status = -1;        //zzz should handle more than 2 pages for 400/800 mbps.
  4526.         
  4527.         packetPageCount += pageCount;
  4528.         
  4529.         pDCLTransferPacket = (DCLTransferPacketPtr) pDCLTransferPacket->pNextDCLCommand;
  4530.  
  4531.         if ((pDCLTransferPacket->opcode & ~kFWDCLOpFlagMask) != kDCLSendPacketOp)
  4532.         {
  4533.             pDCLTransferPacket = nil;
  4534.         }
  4535.     } while (pDCLTransferPacket != nil);
  4536.         
  4537.     // Allocate new descriptor.
  4538.     status = PeleFWIMAllocateDMA (pPeleDMABuildState, &pDMA, &pDMAPhys, packetPageCount + 1);
  4539.     
  4540.     pDoDMA = pDMA;
  4541.     // Because Pele synthesizes the packet header for us, it can't take a stream of
  4542.     // OUTPUT_MOREs followed by an OUTPUT_LAST and form up a single isoch packet.
  4543.     // If the packet is bigger than the FIFO, Pele would have to send the header,
  4544.     // with the packet length in it, before it had ever seen the descriptor for the
  4545.     // final part of the packet.  So Pele would not know how big the packet was going
  4546.     // to be until it was too late.
  4547.     
  4548.     // Lynx requires us to form the header in software, where we know how big the
  4549.     // packet is going to be, so Lynx doesn't have this difficulty.
  4550.     
  4551.     // So as a tremendous hack, use the rateMode isochronous transmit, and change "I"
  4552.     // prior to every packet.  This forces Pele to send a packet of size I using as
  4553.     // many descriptors as needed, which we will provide.
  4554.     
  4555.     // Write first descriptor to STORE_QUAD the packet length into I+n/d
  4556.     // zzz shouldn't hardwire to itaControl.
  4557.     if (status == noErr)
  4558.     {
  4559.         pDoDMA->operation =
  4560.             EndianSwap32Bit (kPeleSTORE_QUAD |                    // Write I+n/d register
  4561.                              kPeleKEY_SYSTEM |                    // Works for PCI registers too
  4562.                              kPeleIntNever |                    // No Interrupt
  4563.                              kPeleWaitNever |                    // No wait
  4564.                              4);                                // reqCount
  4565.         pDoDMA->address = EndianSwap32Bit ((UInt32)
  4566.             &(pPeleDMABuildState->pPeleFWIMData->pPeleRegisters->itaControl.bandwidthControl));
  4567.         pDoDMA->cmdDep = EndianSwap32Bit (packetSize << 16);    // data.
  4568.         pDoDMA->result = EndianSwapImm32Bit (0);                // modified when DMA complete
  4569.         
  4570.         pDoDMA++;
  4571.     }
  4572.  
  4573.     // Set up payload descriptors.
  4574.     if (status == noErr)
  4575.     {
  4576.         for (doPage = 0; doPage < packetPageCount; doPage++)
  4577.         {
  4578.             pDoDMA->operation =
  4579.                 EndianSwap32Bit (kPeleKEY_STREAM0 |                // Only STREAM implemented
  4580.                                  kPeleIntNever |                // No Interrupt
  4581.                                  kPeleBranchNever |                // Go on to next descriptor
  4582.                                  kPeleWaitNever |                // No wait
  4583.                                  sizeTable[doPage]);            // reqCount
  4584.                                  
  4585.             // Doesn't actually matter if we use MORE or LAST, but pretend it does:
  4586.             
  4587.             if (doPage + 1 == packetPageCount)
  4588.                 pDoDMA->operation |= EndianSwapImm32Bit (kPeleOUTPUT_LAST);
  4589.                 else pDoDMA->operation |= EndianSwapImm32Bit (kPeleOUTPUT_MORE);
  4590.             pDoDMA->address = EndianSwap32Bit ((UInt32) physTable[doPage]);
  4591.             pDoDMA->cmdDep = EndianSwapImm32Bit (0);        // branch address - may be filled in later.
  4592.             pDoDMA->result = EndianSwapImm32Bit (0);        // modified when DMA complete
  4593.             
  4594.             pDoDMA++;
  4595.         }
  4596.         pDoDMA--;        // point to final DMA
  4597.         pDoDMA->operation |= EndianSwapImm32Bit (kPeleBranchAlways);
  4598.     }
  4599.     
  4600.     // Link previous descriptor.
  4601.     if ((status == noErr) && pPeleDMABuildState->pLastBranch)
  4602.     {
  4603.         *(pPeleDMABuildState->pLastBranch) = EndianSwap32Bit ((UInt32) pDMAPhys);
  4604.     }
  4605.  
  4606.     // Update build state.
  4607.     if (status == noErr)
  4608.     {
  4609.         // Our last descriptor doesn't yet have a branch address.  Here's where it goes:
  4610.         pPeleDMABuildState->pLastBranch = (UInt32 *) &(pDoDMA->cmdDep);
  4611.     }
  4612.     
  4613.     // Return results.
  4614.     //zzz should fill in CompilerDCLData for SendPacketOps we compiled.
  4615.     // but I don't think it ever gets used, unless we update buffers (NYI anyway)
  4616.     if (status == noErr)
  4617.     {
  4618.         pPeleDCLCompilerDCLData->pDMA = pDMA;
  4619.         pPeleDCLCompilerDCLData->pDMAPhys = pDMAPhys;
  4620.     }
  4621.     else
  4622.     {
  4623.         pPeleDCLCompilerDCLData->pDMA = nil;
  4624.         pPeleDCLCompilerDCLData->pDMAPhys = nil;
  4625.     }
  4626.  
  4627.     return status;
  4628. }
  4629.  
  4630.  
  4631. ////////////////////////////////////////////////////////////////////////////////
  4632. //
  4633. // PeleFWIMAddSendPacketWithHeaderStartDCL
  4634. //
  4635. //   This proc adds a send packet with header start DCL.
  4636. //zzz need to be able to specify speed.
  4637. //
  4638.  
  4639. static OSStatus PeleFWIMAddSendPacketWithHeaderStartDCL(
  4640.     PeleDMABuildStatePtr        pPeleDMABuildState,
  4641.     DCLCommandPtr                pDCLCommand)
  4642. {
  4643. //zzz I think this could be a special case of SendPacketStart, where we examine the header
  4644. // and write a STORE_QUAD to configure the isoch transmitter accordingly before each packet.
  4645. // We'll have to re-examine the header after each Update.
  4646.  
  4647.     FWDebugStr ((ConstStr255Param) "\pPeleFWIMAddSendPacketWithHeaderStartDCL is not supported");
  4648.     return -1;
  4649. }
  4650.  
  4651.  
  4652. ////////////////////////////////////////////////////////////////////////////////
  4653. //
  4654. // PeleFWIMAddSendPacketDCL
  4655. //
  4656. //   This proc adds a send packet DCL.
  4657. //   zzz In case it doesn't get documented anywhere else, the DCL "SendPacket"
  4658. //   actually means send *part* of a packet.  All consecutive SendPackets will
  4659. //   be merged together with the previous SendPacketStart, to form a single packet.
  4660. //   The same is true of ReceivePacket.
  4661. //
  4662. //   There's nothing to do here, because we already processed this when we saw
  4663. //   the preceeding SendPacketStartOp.
  4664.  
  4665. static OSStatus PeleFWIMAddSendPacketDCL(
  4666.     PeleDMABuildStatePtr        pPeleDMABuildState,
  4667.     DCLCommandPtr                pDCLCommand)
  4668. {
  4669.     return noErr;
  4670. }
  4671.  
  4672.  
  4673. ////////////////////////////////////////////////////////////////////////////////
  4674. //
  4675. //zzz rename to AddInterruptDMA or something, call directly.
  4676. // PeleFWIMAddCallProcDCL
  4677. //
  4678. //   This proc compiles a call proc DCL into three descriptors.
  4679. //
  4680.  
  4681. static OSStatus PeleFWIMAddCallProcDCL(
  4682.     PeleDMABuildStatePtr        pPeleDMABuildState,
  4683.     DCLCommandPtr                pDCLCommand)
  4684. {
  4685.     PeleDCLCompilerDCLDataPtr    pPeleDCLCompilerDCLData;
  4686.     PeleDMAPtr                    pDMA, pDoDMA;
  4687.     PhysicalAddress                pDMAPhys;
  4688.     PeleFWIMDataPtr                pPeleFWIMData, physPeleFWIMData;
  4689.     UInt32                        dmaChannelNum;
  4690.     OSStatus                    status = noErr;
  4691.     
  4692.     pPeleDCLCompilerDCLData = (PeleDCLCompilerDCLDataPtr) pDCLCommand->compilerData;
  4693.  
  4694.     // Get Pele FWIM data.
  4695.     pPeleFWIMData = pPeleDMABuildState->pPeleFWIMData;
  4696.     physPeleFWIMData = (PeleFWIMDataPtr) pPeleFWIMData->fwimDataPhys;
  4697.     dmaChannelNum = pPeleDMABuildState->dmaChannelNum;
  4698.  
  4699.     // Allocate new descriptors.
  4700.     status = PeleFWIMAllocateDMA (pPeleDMABuildState, &pDMA, &pDMAPhys, 3);
  4701.     
  4702.     // Set up descriptors.
  4703.     if (status == noErr)
  4704.     {
  4705.         pDoDMA = pDMA;
  4706.         
  4707.         // Load current interrupt link and stash it in this descriptor
  4708.         
  4709.         pDoDMA->operation =
  4710.             EndianSwapImm32Bit (kPeleLOAD_QUAD |        // Load current interrupt queue
  4711.                                 kPeleKEY_SYSTEM |
  4712.                                 kPeleIntNever |            // No interrupt
  4713.                                 kPeleWaitNever |        // No wait
  4714.                                 4);                        // reqCount
  4715.         pDoDMA->address =
  4716.             EndianSwap32Bit ((UInt32) &(physPeleFWIMData->pDCLInterruptTail[dmaChannelNum]));
  4717.         pDoDMA->cmdDep = EndianSwapImm32Bit (0);        // Will be filled by load.
  4718.         pDoDMA->result = EndianSwapImm32Bit (0);        // modified when DMA complete
  4719.  
  4720.         pDoDMA++;
  4721.         
  4722.         // Store our DCL pointer into the tail pointer
  4723.         
  4724.         pDoDMA->operation =
  4725.             EndianSwapImm32Bit (kPeleSTORE_QUAD |        // Store ourselves at queue tail
  4726.                                 kPeleKEY_SYSTEM |
  4727.                                 kPeleIntNever |            // No interrupt
  4728.                                 kPeleWaitNever |        // No wait
  4729.                                 4);                        // reqCount
  4730.         pDoDMA->address =
  4731.             EndianSwap32Bit ((UInt32) &(physPeleFWIMData->pDCLInterruptTail[dmaChannelNum]));
  4732.         pDoDMA->cmdDep = EndianSwap32Bit ((UInt32) pDCLCommand);        // value to store.
  4733.         pDoDMA->result = EndianSwapImm32Bit (0);        // modified when DMA complete
  4734.  
  4735.         pDoDMA++;
  4736.         
  4737.         // LOAD_QUAD and STORE_QUAD don't have branch addresses, so do a NOP and branch.
  4738.         
  4739.         pDoDMA->operation =
  4740.             EndianSwapImm32Bit (kPeleNOP_CMD |            // Do nothing
  4741.                                 kPeleIntAlways |        // ... except Interrupt
  4742.                                 kPeleBranchAlways |        // ... and branch to next descriptor
  4743.                                 kPeleWaitNever);        // No wait
  4744.         pDoDMA->address = EndianSwapImm32Bit (0);
  4745.         pDoDMA->cmdDep = EndianSwapImm32Bit (0);        // branch address - will be filled in later.
  4746.         pDoDMA->result = EndianSwapImm32Bit (0);        // modified when DMA complete
  4747.     }
  4748.     
  4749.     // Link previous descriptor.
  4750.     if ((status == noErr) && pPeleDMABuildState->pLastBranch)
  4751.     {
  4752.         *(pPeleDMABuildState->pLastBranch) = EndianSwap32Bit ((UInt32) pDMAPhys);
  4753.     }
  4754.  
  4755.     // Update build state.
  4756.     if (status == noErr)
  4757.     {
  4758.         // Our new descriptor doesn't yet have a branch address.  Here's where it goes:
  4759.         pPeleDMABuildState->pLastBranch = (UInt32 *) &(pDoDMA->cmdDep);
  4760.     }
  4761.     
  4762.     // Return results.
  4763.     if (status == noErr)
  4764.     {
  4765.         pPeleDCLCompilerDCLData->pDMA = pDMA;
  4766.         pPeleDCLCompilerDCLData->pDMAPhys = pDMAPhys;
  4767.     }
  4768.     else
  4769.     {
  4770.         pPeleDCLCompilerDCLData->pDMA = nil;
  4771.         pPeleDCLCompilerDCLData->pDMAPhys = nil;
  4772.     }
  4773.  
  4774.     return status;
  4775. }
  4776.  
  4777.  
  4778. ////////////////////////////////////////////////////////////////////////////////
  4779. //
  4780. // PeleFWIMAddJumpDCL
  4781. //
  4782. //   This proc adds a jump DCL.
  4783. //
  4784.  
  4785. static OSStatus PeleFWIMAddJumpDCL(
  4786.     PeleDMABuildStatePtr        pPeleDMABuildState,
  4787.     DCLCommandPtr                pDCLCommand)
  4788. {
  4789.     PeleDCLCompilerDCLDataPtr    pPeleDCLCompilerDCLData;
  4790.     PeleDMAPtr                    pDMA;
  4791.     PhysicalAddress                pDMAPhys;
  4792.     DCLJumpPtr                    pDCLJump;
  4793.     DCLLabelPtr                    pDCLLabel;
  4794.     PeleDCLCompilerDCLDataPtr    pLabelPeleDCLCompilerDCLData;
  4795.     UInt32                        branchTargetPhys;
  4796.     OSStatus                    status = noErr;
  4797.  
  4798.     FWDebugStr ((ConstStr255Param) "\p PeleFWIMAddJumpDCL");
  4799.     
  4800.     // Recast DCL commands.
  4801.     pDCLJump = (DCLJumpPtr) pDCLCommand;        
  4802.     pPeleDCLCompilerDCLData = (PeleDCLCompilerDCLDataPtr) pDCLJump->compilerData;
  4803.     
  4804.     pDCLLabel = (DCLLabelPtr) pDCLJump->pJumpDCLLabel;
  4805.     pLabelPeleDCLCompilerDCLData = (PeleDCLCompilerDCLDataPtr) pDCLLabel->compilerData;
  4806.     
  4807.     // Allocate new descriptor.
  4808.     status = PeleFWIMAllocateDMA (pPeleDMABuildState, &pDMA, &pDMAPhys, 1);
  4809.  
  4810.     if (status == noErr)
  4811.     {
  4812.         pDMA->operation =
  4813.             EndianSwapImm32Bit (kPeleNOP_CMD |            // Do nothing
  4814.                                 kPeleBranchAlways |        // ... except branch
  4815.                                 kPeleIntNever |            // No interrupt
  4816.                                 kPeleWaitNever);        // No wait
  4817.         pDMA->address = EndianSwapImm32Bit (0);
  4818.         pDMA->cmdDep = EndianSwapImm32Bit (0);            // Fill in with branch address
  4819.         pDMA->result = EndianSwapImm32Bit (0);            // modified when DMA complete
  4820.     }
  4821.     
  4822.     // Check if label has been resolved.
  4823.     
  4824.     if (pLabelPeleDCLCompilerDCLData->pDMA != nil)
  4825.     {
  4826.         FWDebugStr ((ConstStr255Param) "\p     ... PeleFWIMAddJumpDCL to resolved label");
  4827.     
  4828.         // Assume that we never jump to nil
  4829.         
  4830.         branchTargetPhys = (UInt32) pLabelPeleDCLCompilerDCLData->pDMAPhys;
  4831.             
  4832. #ifdef PeleVMDebug
  4833. zzz fix this
  4834.         if (((Ptr) (pDCLLabelPCL)) !=
  4835.             ((Ptr) (branchTargetPhys)))
  4836.         {
  4837.             sprintf (debugStr, "Jump target   logical %08lx != physical %08lx",
  4838.                      (long) pDCLLabelPCL,
  4839.                      (long) branchTargetPhys);
  4840.             FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  4841.         }
  4842. #endif
  4843.         pDMA->cmdDep = EndianSwap32Bit ((UInt32) branchTargetPhys);
  4844.  
  4845.     }
  4846.     else
  4847.     {
  4848.         FWDebugStr ((ConstStr255Param) "\p     ... PeleFWIMAddJumpDCL to UNRESOLVED label");
  4849.  
  4850.         // In case the DCL we're branching to already has one unresolved
  4851.         // reference, store that one in our branch field so we can put our
  4852.         // own address in the DCL.  See next comment.
  4853.         
  4854.         pDMA->cmdDep = (UInt32) (pLabelPeleDCLCompilerDCLData->pDMA);
  4855.  
  4856.         // Need to resolve label later.
  4857.         // This is tricky.  Store the (logical) address of the (physical) jump
  4858.         // target address in compilerData.  Later, we'll update it.  Note that
  4859.         // if the spot to be updated contains another address (from previous
  4860.         // line) then we'll update that one too, and so on.
  4861.         pLabelPeleDCLCompilerDCLData->pDMA = (PeleDMAPtr) &(pDMA->cmdDep);
  4862.         
  4863.         // The resolution of all this is done by PeleFWIMResolveDCLLabel.
  4864.         // Labels are resolved as soon as they are added, but we might be
  4865.         // branching to a label that hasn't yet been added (it follows us).
  4866.     }
  4867.  
  4868.     // Link previous descriptor.
  4869.     if ((status == noErr) && pPeleDMABuildState->pLastBranch)
  4870.     {
  4871.         *(pPeleDMABuildState->pLastBranch) = EndianSwap32Bit ((UInt32) pDMAPhys);
  4872.     }
  4873.  
  4874.     // Update build state.
  4875.     if (status == noErr)
  4876.     {
  4877.         // Our new descriptor doesn't need a branch address like others do.
  4878.         pPeleDMABuildState->pLastBranch = nil;
  4879.     }
  4880.     
  4881.     // Return results.
  4882.     if (status == noErr)
  4883.     {
  4884.         pPeleDCLCompilerDCLData->pDMA = pDMA;
  4885.         pPeleDCLCompilerDCLData->pDMAPhys = pDMAPhys;
  4886.     }
  4887.     else
  4888.     {
  4889.         pPeleDCLCompilerDCLData->pDMA = nil;
  4890.         pPeleDCLCompilerDCLData->pDMAPhys = nil;
  4891.     }
  4892.  
  4893.     return status;
  4894. }
  4895.  
  4896.  
  4897. ////////////////////////////////////////////////////////////////////////////////
  4898. //
  4899. // PeleFWIMAddLabelDCL
  4900. //
  4901. //   This proc adds a label DCL.
  4902. //zzz not optimal.
  4903. //
  4904.  
  4905. static OSStatus PeleFWIMAddLabelDCL(
  4906.     PeleDMABuildStatePtr        pPeleDMABuildState,
  4907.     DCLCommandPtr                pDCLCommand)
  4908. {
  4909.     DCLLabelPtr                    pDCLLabel;
  4910.     PeleDCLCompilerDCLDataPtr    pPeleDCLCompilerDCLData;
  4911.     PeleDMAPtr                    pDMA;
  4912.     PhysicalAddress                pDMAPhys;
  4913.     OSStatus                    status = noErr;
  4914.  
  4915.     FWDebugStr ((ConstStr255Param) "\p PeleFWIMAddLabelDCL");
  4916.     
  4917.     // Recast DCL command.
  4918.     pDCLLabel = (DCLLabelPtr) pDCLCommand;
  4919.     pPeleDCLCompilerDCLData = (PeleDCLCompilerDCLDataPtr) pDCLLabel->compilerData;
  4920.     
  4921.     // Allocate new descriptor.
  4922.     status = PeleFWIMAllocateDMA (pPeleDMABuildState, &pDMA, &pDMAPhys, 1);
  4923.  
  4924.     if (status == noErr)
  4925.     {
  4926.         pDMA->operation =
  4927.             EndianSwapImm32Bit (kPeleNOP_CMD |            // Do nothing
  4928.                                 kPeleBranchAlways |        // ... except branch
  4929.                                 kPeleIntNever |            // No interrupt
  4930.                                 kPeleWaitNever);        // No wait
  4931.         pDMA->address = EndianSwapImm32Bit (0);
  4932.         pDMA->cmdDep = EndianSwapImm32Bit (0);            // Fill in with branch address
  4933.         pDMA->result = EndianSwapImm32Bit (0);            // modified when DMA complete
  4934.     }
  4935.  
  4936.     // Resolve label.
  4937.     // This is complicated.  If there were no PCL for a label DCL, we would want
  4938.     // to resolve things that point to us (pDCLCommand) to point to the PCL for
  4939.     // the next "real" command (a transmit, or whatever).  But the next DCL has
  4940.     // not yet been compiled, (and it might be another label), so the PCL that we
  4941.     // would really like to point to doesn't exist yet.
  4942.     //
  4943.     // I think that what we do is have a dummy PCL that does correspond to this
  4944.     // label.  That PCL just does a NOP and falls through to the next PCL (which
  4945.     // doesn't exist yet).  That's what PeleFWIMPCLLabel created.  So we waste a
  4946.     // PCL and add a little latency to jumps, because once we jump to this label
  4947.     // we have to fall through at least one dummy PCL before we get any work done.
  4948.     //
  4949.     // A possible future optimization would be to pre-allocate the next non-label
  4950.     // PCL, so that we know where it is and we can jump to it, rather than making
  4951.     // a dummy PCL as the target.  That could be tricky because pre-allocation
  4952.     // could constrain us.
  4953.     //
  4954.     // A possible alternative optimization would be to take the finished PCL
  4955.     // program, and scan through it for jumps to NOPs, and bump them forward to
  4956.     // the next real command.  That could also be tricky if we try to make changes
  4957.     // to the program later, though.
  4958.     
  4959.     if (status == noErr)
  4960.     {
  4961.         // ResolveDCLLabel will need this.  Could we just pass it as an argument instead?
  4962.         
  4963.         pPeleDCLCompilerDCLData->pDMAPhys = pDMAPhys;
  4964.  
  4965.         status = PeleFWIMResolveDCLLabel (pDCLLabel);
  4966.     }
  4967.     
  4968.     // Link previous descriptor.
  4969.     if ((status == noErr) && pPeleDMABuildState->pLastBranch)
  4970.     {
  4971.         *(pPeleDMABuildState->pLastBranch) = EndianSwap32Bit ((UInt32) pDMAPhys);
  4972.     }
  4973.  
  4974.     // Update build state.
  4975.     if (status == noErr)
  4976.     {
  4977.         // Our new descriptor doesn't yet have a branch address.  Here's where it goes:
  4978.         pPeleDMABuildState->pLastBranch = (UInt32 *) &(pDMA->cmdDep);
  4979.     }
  4980.     
  4981.     // Return results.
  4982.     if (status == noErr)
  4983.     {
  4984.         pPeleDCLCompilerDCLData->pDMA = pDMA;
  4985.         pPeleDCLCompilerDCLData->pDMAPhys = pDMAPhys;
  4986.     }
  4987.     else
  4988.     {
  4989.         pPeleDCLCompilerDCLData->pDMA = nil;
  4990.         pPeleDCLCompilerDCLData->pDMAPhys = nil;
  4991.     }
  4992.     
  4993.     return status;
  4994. }
  4995.  
  4996.  
  4997. ////////////////////////////////////////////////////////////////////////////////
  4998. //
  4999. // PeleFWIMAddSetTagSyncBitsDCL
  5000. //
  5001. //   This proc adds a set tag and sync bits DCL.
  5002. //
  5003.  
  5004. static OSStatus PeleFWIMAddSetTagSyncBitsDCL(
  5005.     PeleDMABuildStatePtr        pPeleDMABuildState,
  5006.     DCLCommandPtr                pDCLCommand)
  5007. {
  5008.     DCLSetTagSyncBitsPtr        pDCLSetTagSyncBits;
  5009.     PeleDCLCompilerDCLDataPtr    pPeleDCLCompilerDCLData;
  5010.     PeleDMAPtr                    pDMA, pDoDMA;
  5011.     PhysicalAddress                pDMAPhys;
  5012.     PeleFWIMDataPtr                pPeleFWIMData;
  5013.     PeleRegistersPtr            pPeleRegs;
  5014.     UInt32                        itdmaConfig;
  5015.     OSStatus                    status = noErr;
  5016.     
  5017.     // Recast DCL command.
  5018.     pDCLSetTagSyncBits = (DCLSetTagSyncBitsPtr) pDCLCommand;
  5019.  
  5020.     pPeleDCLCompilerDCLData = (PeleDCLCompilerDCLDataPtr) pDCLCommand->compilerData;
  5021.  
  5022.     // Get Pele FWIM data.
  5023.     pPeleFWIMData = pPeleDMABuildState->pPeleFWIMData;
  5024.     pPeleRegs = pPeleFWIMData->pPeleRegisters;
  5025.  
  5026.     // Allocate new descriptors.
  5027.     status = PeleFWIMAllocateDMA (pPeleDMABuildState, &pDMA, &pDMAPhys, 2);
  5028.     
  5029.     // Set up descriptors.
  5030.     if (status == noErr)
  5031.     {
  5032.         itdmaConfig = pDCLSetTagSyncBits->tagBits << kPeleITDMAconfigTagPhase;
  5033.         itdmaConfig |= pPeleDMABuildState->isochChannelNum << kPeleITDMAconfigChannelPhase;
  5034.         // zzz should set correct tx speed (defaults to s100)
  5035.         itdmaConfig |= pDCLSetTagSyncBits->syncBits << kPeleITDMAconfigSyncPhase;
  5036.         itdmaConfig |= kPeleITDMAconfigRateMode;
  5037.         
  5038.         // Now here's the hard part:  We will overwrite the startOnEvent and stopOnEvent
  5039.         // bits.  We don't care about stopOnEvent, but there are two possible cases for
  5040.         // startOnEvent:  1, the channel has not yet started running, so startOnEvent
  5041.         // should be 01 (start on cycle).  2, the channel is already running, so startOnEvent
  5042.         // should be 11 (in progress).
  5043.         // I believe that changing 01 to 11 may cause the DMA to start immediately.
  5044.         // Likewise, changing 11 to 01 might stop the DMA until the next match.
  5045.         // What to do...?
  5046.         //
  5047.         // Hmm, could use 01 the first time, then once the DMA gets going, go change that to
  5048.         // 11 so it will work on future passes.  That's messy, we have to find each setTagSync
  5049.         // prior to the first OUTPUT and then fix them up.
  5050.         //
  5051.         // Try just setting it to 11.  Experiments show that this causes the DMA to run immediately.
  5052.         // That doesn't agree with our desired start-on-cylce, but maybe the timestamps gathered
  5053.         // by the DV transmit program will allow it to get things cleaned up later.  (ugh)
  5054.                 
  5055.         itdmaConfig |= (kPeleEventOccured << kPeleITDMAconfigStartOnEventPhase);
  5056.  
  5057.         pDoDMA = pDMA;
  5058.         
  5059.         // Store new tag and sync values in ITDMA config register
  5060.         //zzz hardwired to ITA
  5061.         
  5062.         pDoDMA->operation =
  5063.             EndianSwapImm32Bit (kPeleSTORE_QUAD |        // Store new settings
  5064.                                 kPeleKEY_SYSTEM |
  5065.                                 kPeleIntNever |            // No interrupt
  5066.                                 kPeleWaitNever |        // No wait
  5067.                                 4);                        // reqCount
  5068.         pDoDMA->address = EndianSwap32Bit ((UInt32) &(pPeleRegs->itaControl.configuration));
  5069.         pDoDMA->cmdDep = EndianSwapImm32Bit (itdmaConfig);    // New config settings
  5070.         pDoDMA->result = EndianSwapImm32Bit (0);            // modified when DMA complete
  5071.  
  5072.         pDoDMA++;
  5073.         
  5074.         // STORE_QUAD has no branch address, so do a NOP and branch.
  5075.         
  5076.         pDoDMA->operation =
  5077.             EndianSwapImm32Bit (kPeleNOP_CMD |            // Do nothing
  5078.                                 kPeleIntAlways |        // ... except Interrupt
  5079.                                 kPeleBranchAlways |        // ... and branch to next descriptor
  5080.                                 kPeleWaitNever);        // No wait
  5081.         pDoDMA->address = EndianSwapImm32Bit (0);
  5082.         pDoDMA->cmdDep = EndianSwapImm32Bit (0);        // branch address - will be filled in later.
  5083.         pDoDMA->result = EndianSwapImm32Bit (0);        // modified when DMA complete
  5084.  
  5085.     }
  5086.     
  5087.     // Link previous descriptor.
  5088.     if ((status == noErr) && pPeleDMABuildState->pLastBranch)
  5089.     {
  5090.         *(pPeleDMABuildState->pLastBranch) = EndianSwap32Bit ((UInt32) pDMAPhys);
  5091.     }
  5092.  
  5093.     // Update build state.
  5094.     if (status == noErr)
  5095.     {
  5096.         // Our new descriptor doesn't yet have a branch address.  Here's where it goes:
  5097.         pPeleDMABuildState->pLastBranch = (UInt32*) &(pDoDMA->cmdDep);
  5098.     }
  5099.     
  5100.     // Return results.
  5101.     if (status == noErr)
  5102.     {
  5103.         pPeleDCLCompilerDCLData->pDMA = pDMA;
  5104.         pPeleDCLCompilerDCLData->pDMAPhys = pDMAPhys;
  5105.     }
  5106.     else
  5107.     {
  5108.         pPeleDCLCompilerDCLData->pDMA = nil;
  5109.         pPeleDCLCompilerDCLData->pDMAPhys = nil;
  5110.     }
  5111.  
  5112.     return status;
  5113. }
  5114.  
  5115.  
  5116. ////////////////////////////////////////////////////////////////////////////////
  5117. //
  5118. // PeleFWIMAddUpdateDCLListDCL
  5119. //
  5120. //   This proc adds a update DCL list DCL.
  5121. //
  5122.  
  5123. static OSStatus PeleFWIMAddUpdateDCLListDCL(
  5124.     PeleDMABuildStatePtr        pPeleDMABuildState,
  5125.     DCLCommandPtr                pDCLCommand)
  5126. {
  5127.     // These just do the same thing - add an interrupt and sort it out later.
  5128.     return PeleFWIMAddCallProcDCL (pPeleDMABuildState, pDCLCommand);
  5129. }
  5130.  
  5131.  
  5132. ////////////////////////////////////////////////////////////////////////////////
  5133. //
  5134. // PeleFWIMAddTimeStampDCL
  5135. //
  5136. //   This proc adds a time stamp DCL.  This will build PCL commands to read the
  5137. // current cycle counter and write it into the PCL command.  The DCL compiler data
  5138. // will point to where the cycle timer is stored in the PCL command.
  5139. //
  5140.  
  5141. static OSStatus PeleFWIMAddTimeStampDCL(
  5142.     PeleDMABuildStatePtr        pPeleDMABuildState,
  5143.     DCLCommandPtr                pDCLCommand)
  5144. {
  5145.     PeleDCLCompilerDCLDataPtr    pPeleDCLCompilerDCLData;
  5146.     PeleDMAPtr                    pDMA, pDoDMA;
  5147.     PhysicalAddress                pDMAPhys;
  5148.     PeleFWIMDataPtr                pPeleFWIMData;
  5149.     PeleRegistersPtr            pPeleRegs;
  5150.     OSStatus                    status = noErr;
  5151.     
  5152.     pPeleDCLCompilerDCLData = (PeleDCLCompilerDCLDataPtr) pDCLCommand->compilerData;
  5153.  
  5154.     // Get Pele FWIM data.
  5155.     pPeleFWIMData = pPeleDMABuildState->pPeleFWIMData;
  5156.     pPeleRegs = pPeleFWIMData->pPeleRegisters;
  5157.  
  5158.     // Allocate new descriptors.
  5159.     status = PeleFWIMAllocateDMA (pPeleDMABuildState, &pDMA, &pDMAPhys, 2);
  5160.     
  5161.     // Set up descriptors.
  5162.     if (status == noErr)
  5163.     {        
  5164.         pDoDMA = pDMA;
  5165.         
  5166.         // Stash a copy of the cycle timer register in the first descriptor
  5167.         
  5168.         pDoDMA->operation =
  5169.             EndianSwapImm32Bit (kPeleLOAD_QUAD |        // Store new settings
  5170.                                 kPeleKEY_SYSTEM |
  5171.                                 kPeleIntNever |            // No interrupt
  5172.                                 kPeleWaitNever |        // No wait
  5173.                                 4);                        // reqCount
  5174.         pDoDMA->address = EndianSwap32Bit ((UInt32) &(pPeleRegs->isochronousCycleTimer));
  5175.         pDoDMA->cmdDep = EndianSwapImm32Bit (0);        // Will load it here
  5176.         pDoDMA->result = EndianSwapImm32Bit (0);        // modified when DMA complete
  5177.  
  5178.         pDoDMA++;
  5179.         
  5180.         // LOAD_QUAD has no branch address, so do a NOP and branch.
  5181.         
  5182.         pDoDMA->operation =
  5183.             EndianSwapImm32Bit (kPeleNOP_CMD |            // Do nothing
  5184.                                 kPeleIntAlways |        // ... except Interrupt
  5185.                                 kPeleBranchAlways |        // ... and branch to next descriptor
  5186.                                 kPeleWaitNever);        // No wait
  5187.         pDoDMA->address = EndianSwapImm32Bit (0);
  5188.         pDoDMA->cmdDep = EndianSwapImm32Bit (0);        // branch address - will be filled in later.
  5189.         pDoDMA->result = EndianSwapImm32Bit (0);        // modified when DMA complete
  5190.  
  5191.     }
  5192.     
  5193.     // Link previous descriptor.
  5194.     if ((status == noErr) && pPeleDMABuildState->pLastBranch)
  5195.     {
  5196.         *(pPeleDMABuildState->pLastBranch) = EndianSwap32Bit ((UInt32) pDMAPhys);
  5197.     }
  5198.  
  5199.     // Update build state.
  5200.     if (status == noErr)
  5201.     {
  5202.         // Our new descriptor doesn't yet have a branch address.  Here's where it goes:
  5203.         pPeleDMABuildState->pLastBranch = (UInt32 *) &(pDoDMA->cmdDep);
  5204.     }
  5205.     
  5206.     // Return results.
  5207.     if (status == noErr)
  5208.     {
  5209.         pPeleDCLCompilerDCLData->pDMA = pDMA;
  5210.         pPeleDCLCompilerDCLData->pDMAPhys = pDMAPhys;
  5211.     }
  5212.     else
  5213.     {
  5214.         pPeleDCLCompilerDCLData->pDMA = nil;
  5215.         pPeleDCLCompilerDCLData->pDMAPhys = nil;
  5216.     }
  5217.  
  5218.     return status;
  5219. }
  5220.  
  5221.  
  5222. ////////////////////////////////////////////////////////////////////////////////
  5223. //
  5224. // PeleFWIMAddStopDCL
  5225. //
  5226. //   This proc adds a (virtual) Stop DCL.
  5227. //
  5228.  
  5229. static OSStatus PeleFWIMAddStopDCL(
  5230.     PeleDMABuildStatePtr        pPeleDMABuildState)
  5231. {
  5232.     PeleDMAPtr                    pDMA;
  5233.     PhysicalAddress                pDMAPhys;
  5234.     PeleFWIMDataPtr                pPeleFWIMData;
  5235.     OSStatus                    status = noErr;
  5236.     
  5237.     // Get Pele FWIM data.
  5238.     pPeleFWIMData = pPeleDMABuildState->pPeleFWIMData;
  5239.  
  5240.     // Allocate new descriptor.
  5241.     status = PeleFWIMAllocateDMA (pPeleDMABuildState, &pDMA, &pDMAPhys, 1);
  5242.     
  5243.     // Set up descriptor.
  5244.     if (status == noErr)
  5245.     {
  5246.         pDMA->operation = EndianSwapImm32Bit (kPeleSTOP_CMD);
  5247.         pDMA->address = EndianSwapImm32Bit (0);
  5248.         pDMA->cmdDep = EndianSwapImm32Bit (0);    
  5249.         pDMA->result = EndianSwapImm32Bit (0);
  5250.     }
  5251.     
  5252.     // Link previous descriptor.
  5253.     if ((status == noErr) && pPeleDMABuildState->pLastBranch)
  5254.     {
  5255.         *(pPeleDMABuildState->pLastBranch) = EndianSwap32Bit ((UInt32) pDMAPhys);
  5256.     }
  5257.  
  5258.     // Update build state.
  5259.     if (status == noErr)
  5260.     {
  5261.         pPeleDMABuildState->pLastBranch = nil;
  5262.     }
  5263.     
  5264.     return status;
  5265. }
  5266.  
  5267.  
  5268. ////////////////////////////////////////////////////////////////////////////////
  5269. //
  5270. // PeleFWIMDMAStart
  5271. //
  5272. //   This proc creates a build state record and a NOP descriptor to start the
  5273. // program.
  5274. //
  5275.  
  5276. static OSStatus    PeleFWIMDMAStart(
  5277.     PeleFWIMDataPtr                pPeleFWIMData,
  5278.     PeleDMABuildStatePtr        *ppPeleDMABuildState,
  5279.     PeleDMAPtr                    *ppStartDMA)
  5280. {
  5281.     PeleDMABuildStatePtr        pPeleDMABuildState;
  5282.     PeleDMAPtr                    pDMA;
  5283.     PhysicalAddress                pDMAPhys;
  5284.     OSStatus                    status = noErr;
  5285.     
  5286.     // Probably don't need any of this
  5287.     
  5288.     // Allocate build state record.
  5289.     status = PeleFWIMAllocateDMABuildState (pPeleFWIMData, &pPeleDMABuildState);
  5290.     
  5291.     // Allocate new descriptor.
  5292.     if (status == noErr)
  5293.         status = PeleFWIMAllocateDMA (pPeleDMABuildState, &pDMA, &pDMAPhys, 1);
  5294.     
  5295.     // Set up descriptor.
  5296.     if (status == noErr)
  5297.     {        
  5298.         pDMA->operation =
  5299.             EndianSwapImm32Bit (kPeleNOP_CMD |            // do nothing
  5300.                                 kPeleBranchAlways |        // ... except branch
  5301.                                 kPeleIntNever |            // No interrupt
  5302.                                 kPeleWaitNever);        // No wait
  5303.         pDMA->address = EndianSwapImm32Bit (0);
  5304.         pDMA->cmdDep = EndianSwapImm32Bit (0);
  5305.         pDMA->result = EndianSwapImm32Bit (0);            // modified when DMA complete
  5306.     }
  5307.     
  5308.     // Fill in build state record.
  5309.     if (status == noErr)
  5310.     {
  5311.         pPeleDMABuildState->pPeleFWIMData = pPeleFWIMData;
  5312.         
  5313.         // Our new descriptor doesn't yet have a branch address.  Here's where it goes:
  5314.         pPeleDMABuildState->pLastBranch = (UInt32 *) &(pDMA->cmdDep);
  5315.     }
  5316.     
  5317.     // Return results.
  5318.     if (status == noErr)
  5319.     {
  5320.         *ppPeleDMABuildState = pPeleDMABuildState;
  5321.         *ppStartDMA = (PeleDMAPtr) pDMAPhys;        // zzz rename field
  5322.     }
  5323.     else
  5324.     {
  5325.         *ppPeleDMABuildState = nil;
  5326.         *ppStartDMA = nil;
  5327.     }
  5328.     
  5329.     return status;
  5330. }
  5331.  
  5332.  
  5333. ////////////////////////////////////////////////////////////////////////////////
  5334. //
  5335. // PeleFWIMResolveDCLLabel
  5336. //
  5337. //   This proc resolves the given DCL label.
  5338. //
  5339.  
  5340. static OSStatus    PeleFWIMResolveDCLLabel(
  5341.     DCLLabelPtr                    pDCLLabel)
  5342. {
  5343.     PeleDCLCompilerDCLDataPtr    pPeleDCLCompilerDCLData;
  5344.     PeleDMAPtr                    *pLabelDependency,
  5345.                                 *pNextLabelDependency;
  5346.     UInt32                        branchTargetPhys;
  5347.     OSStatus                    status = noErr;
  5348.     
  5349.     FWDebugStr ((ConstStr255Param) "\p PeleFWIMResolveDCLLabel");
  5350.     
  5351.     // The label pDCLLabel has just been added to the PCL program.  It may already
  5352.     // be the branch target of one or more existing PCLs.  If so, they have stashed
  5353.     // a pointer to where they hold their branch target in pDCLLabel->compilerData.
  5354.     // Furthermore, if what is pointed to is not nil, it is another pointer to an
  5355.     // unresolved label, etc.  So we follow that chain, filling in our real PCL
  5356.     // address.  Note that we will need to fill in the physical address, since now
  5357.     // is the final stage in assigning jump addresses.
  5358.     
  5359.     pPeleDCLCompilerDCLData = (PeleDCLCompilerDCLDataPtr) pDCLLabel->compilerData;
  5360.  
  5361.     // Resolve all of the dependencies.
  5362.     if (pPeleDCLCompilerDCLData->pDMA != nil)
  5363.     {
  5364.         //zzz what if label DCL is last in list???
  5365.         
  5366.         // Resolve label to this descriptor.
  5367.         {
  5368.             pLabelDependency = (PeleDMAPtr *) pPeleDCLCompilerDCLData->pDMA;
  5369.             while (pLabelDependency != nil)
  5370.             {
  5371.                 FWDebugStr ((ConstStr255Param) "\p      ... PeleFWIMResolveDCLLabel resolved dependency");
  5372.  
  5373.                 // Assume no branch to nil
  5374.                 
  5375.                 branchTargetPhys = (UInt32) pPeleDCLCompilerDCLData->pDMAPhys;
  5376.                     
  5377.                 pNextLabelDependency = (PeleDMAPtr *) *pLabelDependency;
  5378.                 *pLabelDependency = (PeleDMAPtr) EndianSwap32Bit (branchTargetPhys);
  5379.                 pLabelDependency = pNextLabelDependency;
  5380. #ifdef PeleVMDebug
  5381. zzz fix this
  5382.                 if (((Ptr) (pPCL)) !=
  5383.                     ((Ptr) (branchTargetPhys)))
  5384.                 {
  5385.                     sprintf (debugStr, "Resolved target   logical %08lx != physical %08lx",
  5386.                              (long) pPCL,
  5387.                              (long) branchTargetPhys);
  5388.                     FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  5389.                 }
  5390. #endif
  5391.             }
  5392.         }
  5393.         
  5394.         // resolve is called after we create the label but before we fill in
  5395.         // its compiler data.  this is not really required any more:
  5396.         
  5397.         pPeleDCLCompilerDCLData->pDMA = nil;
  5398.     }
  5399.     
  5400.     return status;
  5401. }
  5402.  
  5403.  
  5404. ////////////////////////////////////////////////////////////////////////////////
  5405. //
  5406. // PeleFWIMDCLCompilerNotification
  5407. //
  5408. //   This proc handles update notifications for the DCL to PCL compiler.
  5409. //
  5410.  
  5411. static OSStatus        PeleFWIMDCLCompilerNotification(
  5412.     DCLProgramID                dclProgramID,
  5413.     UInt32                        notificationType,
  5414.     DCLCommandPtr                *dclCommandList,
  5415.     UInt32                        numDCLCommands)
  5416. {
  5417.     OSStatus                    status = noErr;
  5418.  
  5419.     switch (notificationType)
  5420.     {
  5421.         case kFWDCLUpdateNotification :
  5422.             status = PeleFWIMDCLCompilerUpdateNotification (dclProgramID,
  5423.                                                             dclCommandList,
  5424.                                                             numDCLCommands);
  5425.             break;
  5426.  
  5427.         case kFWDCLModifyNotification :
  5428.             status = PeleFWIMDCLCompilerModifyNotification (dclProgramID,
  5429.                                                             dclCommandList,
  5430.                                                             numDCLCommands);
  5431.             break;
  5432.  
  5433.         default :
  5434.             status = paramErr;
  5435.             break;
  5436.     }
  5437.  
  5438.     return status;
  5439. }
  5440.  
  5441.  
  5442. ////////////////////////////////////////////////////////////////////////////////
  5443. //
  5444. // PeleFWIMDCLCompilerUpdateNotification
  5445. //
  5446. //   This proc handles update notifications for the DCL to PCL compiler.  This will
  5447. // do any neccessary CheckPointIOs and update any DCL status fields.
  5448. //zzz do the right stuff in here
  5449. //
  5450.  
  5451. static OSStatus        PeleFWIMDCLCompilerUpdateNotification(
  5452.     DCLProgramID                dclProgramID,
  5453.     DCLCommandPtr                *dclCommandList,
  5454.     UInt32                        numDCLCommands)
  5455. {
  5456.     DCLCommandPtr                pDCLCommand;
  5457.     UInt32                        dclCommandNum;
  5458.     OSStatus                    status = noErr;
  5459.  
  5460.     for (dclCommandNum = 0; dclCommandNum < numDCLCommands; dclCommandNum++)
  5461.     {
  5462.         pDCLCommand = dclCommandList[dclCommandNum];
  5463.         switch (pDCLCommand->opcode & ~kFWDCLOpFlagMask)
  5464.         {
  5465.             case kDCLTimeStampOp :
  5466.                 PeleFWIMUpdateDCLTimeStamp (pDCLCommand);
  5467.                 break;
  5468.  
  5469.             case kDCLReceivePacketStartOp :
  5470.                 PeleFWIMUpdateDCLReceivePacketStart (pDCLCommand);
  5471.                 break;
  5472.  
  5473.             // I think we might want to CheckpointIO () on the live buffers, etc...?
  5474.             default :
  5475.                 break;
  5476.         }
  5477.     }
  5478.  
  5479.     return status;
  5480. }
  5481.  
  5482.  
  5483. ////////////////////////////////////////////////////////////////////////////////
  5484. //
  5485. // PeleFWIMUpdateDCLTimeStamp
  5486. //
  5487. //   This proc updates a DCL time stamp.  It reads the time stamp out of a
  5488. // descriptor and writes it into the timeStamp field of the DCL.
  5489. //
  5490.  
  5491. static OSStatus        PeleFWIMUpdateDCLTimeStamp(
  5492.     DCLCommandPtr                pDCLCommand)
  5493. {
  5494.     DCLTimeStampPtr                pDCLTimeStamp;
  5495.     PeleDCLCompilerDCLDataPtr    pPeleDCLCompilerDCLData;
  5496.     UInt32                        timeStamp;
  5497.     OSStatus                    status = noErr;
  5498.  
  5499.     // Recast DCL command.
  5500.     pDCLTimeStamp = (DCLTimeStampPtr) pDCLCommand;
  5501.  
  5502.     // Copy time stamp from LOAD_QUAD descriptor.
  5503.     // Add one cycle since we're running ahead.
  5504.     //zzz Actually Pele runs 0 to 1 ahead depending on packet sizes.
  5505.     //zzz can't just add 1, that could result in an illegal cycle #8000
  5506.     //zzz fix add-1 in LynxFWIM too
  5507.     
  5508.     pPeleDCLCompilerDCLData = (PeleDCLCompilerDCLDataPtr) pDCLTimeStamp->compilerData;
  5509.     timeStamp = EndianSwap32Bit (pPeleDCLCompilerDCLData->pDMA->cmdDep);
  5510.     if ((timeStamp >> 12) & 0x1fff == 7999)
  5511.         pDCLTimeStamp->timeStamp = (timeStamp & 0xfe000fff) + (1 << 25);
  5512.         else pDCLTimeStamp->timeStamp = timeStamp + (1 << 12);
  5513.  
  5514.     return status;
  5515. }
  5516.  
  5517.  
  5518. ////////////////////////////////////////////////////////////////////////////////
  5519. //
  5520. // PeleFWIMUpdateDCLReceivePacketStart
  5521. //
  5522. //   This proc updates a receive packet start DCL time stamp.
  5523. //   It fakes the packet header (and should maybe also call checkpointIO).
  5524. //
  5525.  
  5526. static OSStatus        PeleFWIMUpdateDCLReceivePacketStart(
  5527.     DCLCommandPtr                pDCLCommand)
  5528. {
  5529.     DCLTransferPacketPtr        pDCLTransferPacket;
  5530.     PeleDCLCompilerDCLDataPtr    pPeleDCLCompilerDCLData;
  5531.     PeleDMAPtr                    pDMA;
  5532.     UInt32                        receivedCount, result, fakeHeader;
  5533.  
  5534.     // Recast DCL command.
  5535.     pDCLTransferPacket = (DCLTransferPacketPtr) pDCLCommand;
  5536.     pPeleDCLCompilerDCLData = (PeleDCLCompilerDCLDataPtr) pDCLTransferPacket->compilerData;
  5537.  
  5538.     pDMA = pPeleDCLCompilerDCLData->pDMA;
  5539.     result = EndianSwap32Bit (pDMA->result);
  5540.     
  5541.     // Pele stripped the header, so fake one.    
  5542.  
  5543.     receivedCount = (pDCLTransferPacket->size - 4);            // reqCount we gave Pele
  5544.     receivedCount -= (result & kPeleResCountMask);            // subtract resCount to get receive count
  5545.     
  5546.     // Construct fake packet header. Sync and tag are 0.
  5547.     // zzz should fill in channel number
  5548.     
  5549.     fakeHeader = receivedCount << kFWIsochDataLengthPhase;
  5550.     fakeHeader |= kFWTCodeIsochronousBlock << kPelePacketTCodePhase;
  5551.     
  5552.     *((UInt32 *) pDCLTransferPacket->buffer) = fakeHeader;
  5553.     
  5554.     return noErr;
  5555. }
  5556.  
  5557.  
  5558. ////////////////////////////////////////////////////////////////////////////////
  5559. //
  5560. // PeleFWIMDCLCompilerModifyNotification
  5561. //
  5562. //   This proc handles modification notifications for the DCL to PCL compiler.
  5563. //zzz break this routine up
  5564. //
  5565.  
  5566. static OSStatus        PeleFWIMDCLCompilerModifyNotification(
  5567.     DCLProgramID                dclProgramID,
  5568.     DCLCommandPtr                *dclCommandList,
  5569.     UInt32                        numDCLCommands)
  5570. {
  5571.     DCLCommandPtr                pDCLCommand;
  5572.     DCLJumpPtr                    pDCLJump;
  5573.     DCLLabelPtr                    pDCLLabel;
  5574.     PeleDCLCompilerDCLDataPtr    pPeleDCLCompilerDCLData,
  5575.                                 pLabelPeleDCLCompilerDCLData;
  5576.     PeleDMAPtr                    pJumpDMA,
  5577.                                 pLabelDMA;
  5578.  
  5579.     UInt32                        dclCommandNum;
  5580.     UInt32                        branchTargetPhys;
  5581.  
  5582.     OSStatus                    status = noErr;
  5583.  
  5584.     for (dclCommandNum = 0; dclCommandNum < numDCLCommands; dclCommandNum++)
  5585.     {
  5586.         // Get DCL command to update.
  5587.         pDCLCommand = *dclCommandList++;
  5588.         pPeleDCLCompilerDCLData = (PeleDCLCompilerDCLDataPtr) pDCLCommand->compilerData;
  5589.  
  5590.         // Update command.
  5591.         switch (pDCLCommand->opcode & ~kFWDCLOpFlagMask)
  5592.         {
  5593.             case kDCLJumpOp :
  5594.  
  5595.                 // Recast.
  5596.                 pDCLJump = (DCLJumpPtr) pDCLCommand;
  5597.  
  5598.                 // Get label we're jumping to.
  5599.                 pDCLLabel = pDCLJump->pJumpDCLLabel;
  5600.                 pLabelPeleDCLCompilerDCLData = (PeleDCLCompilerDCLDataPtr) pDCLLabel->compilerData;
  5601.  
  5602.                 // Get descriptors for jump and label DCLs.
  5603.                 pJumpDMA = pPeleDCLCompilerDCLData->pDMA;
  5604.                 pLabelDMA = pLabelPeleDCLCompilerDCLData->pDMA;
  5605.  
  5606.                 branchTargetPhys = (UInt32) pLabelPeleDCLCompilerDCLData->pDMAPhys;
  5607.                     
  5608.                 // Update jump descriptor.
  5609.                 pJumpDMA->cmdDep = EndianSwap32Bit ((UInt32) branchTargetPhys);
  5610.  
  5611. #ifdef PeleVMDebug
  5612.                 if (((Ptr) (pLabelPCL)) !=
  5613.                     ((Ptr) (branchTargetPhys)))
  5614.                 {
  5615.                     sprintf (debugStr, "Updated jump   logical %08lx != physical %08lx",
  5616.                              (long) pLabelPCL,
  5617.                              (long) branchTargetPhys);
  5618.                     FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  5619.                 }
  5620. #endif
  5621.                 break;
  5622.  
  5623.             case kDCLSendPacketWithHeaderStartOp :
  5624.                 //zzz support other transfer packet commands.
  5625.  
  5626.                 FWDebugStr ((ConstStr255Param) "/pOops, tried to update buffer, don't know how!");
  5627.  
  5628. // What would we do?
  5629. // We can't do what's done below - that fills in new PCL buffer addresses.  They aren't yet known.
  5630. // What we want is a PrepareMemoryForIO that covers all buffers in the new scheme.  I notice that
  5631. // we don't actually modify the base DCLs - I think we will have to do that.  So make one pass to
  5632. // modify the base DCLs.  Then call the general-purpose memory preparation routine, and let it
  5633. // create an all-new ioPrep (keep the old one).  Once that's done, we can re-scan the list of
  5634. // changes and make updates knowing the new physical addresses.  Finally, once the updates are
  5635. // all in place, it's impossible for any stale DMA to take place, so we can CheckpointIO on
  5636. // the old ioPrep struct and free its resources.  [Technically we should wait one packet to make
  5637. // sure that whatever Pele's current DMA engine is doing is up to date.  Probably a good-enough
  5638. // way to do this is to postpone the CheckpointIO until before the NEXT round of updates, though
  5639. // that is somewhat wasteful if it ties down old buffers that aren't in use anymore...]
  5640. //
  5641. // We should find a safe way to make multiple updates to a PCL.  The user is in trouble anyway
  5642. // if we're changing a PCL while it runs, because they'll get the wrong data, but we want to
  5643. // make sure we don't send an illegally large packet (bad for 1394 bus) or overflow our receiver
  5644. // (could be bad for Pele).  Perhaps we should copy command[0], set it to NOP+last, update the
  5645. // others, then update command[0].  That's safe unless we are inside the PCL but past command[0].
  5646. // After we set command[0] to NOP, we can check the DMA current cmd and make sure it is elsewhere.
  5647. //
  5648. // I don't suppose the user is required to use jump-updates to deactivate part of the program
  5649. // before updating that part?  That would be 100% safe if we know the jump-update worked on time.
  5650. //
  5651. // For safety we should probably pre-allocate a physAddr table and a rangeTable for two ioPrep
  5652. // structs, then we don't have to do any allocs here.  (though PrepareMemForIO might anyway).
  5653. // We know that the total number of buffers can't change, so rangeTable is OK.  When we prepare
  5654. // the physAddr table we should work out both the true size and the worst-case size.  Use the
  5655. // worst-case for alloc, use the true for PrepareMemoryForIO
  5656.  
  5657. #if 0
  5658.                 // Recast.
  5659.                 pDCLTransferPacket = (DCLTransferPacketPtr) pDCLCommand;
  5660.  
  5661.                 // Get PCL.
  5662.                 pTransferPacketPCL =
  5663.                     PeleFWIMGetPCLFromDCL ((DCLCommandPtr) pDCLTransferPacket);
  5664.  
  5665.                 // Update buffer size of transfer PCL.
  5666.                 pclControl = EndianSwap32Bit (pTransferPacketPCL->buffer[0].control);
  5667.                 pclControl = (pclControl & ~kPeleDMA_TransferCount) |
  5668.                              ((pDCLTransferPacket->size) << kPeleDMA_TransferCountPhase);
  5669.                 pTransferPacketPCL->buffer[0].control = EndianSwap32Bit (pclControl);
  5670.  
  5671.                 // Update buffer address of transfer PCL.
  5672.                 // WARNING WARNING this won't work with VM on - this is a logical address
  5673.                 pTransferPacketPCL->buffer[0].address =
  5674.                     (UInt32 *) EndianSwap32Bit ((UInt32) pDCLTransferPacket->buffer);
  5675. #endif
  5676.                 break;
  5677.  
  5678.             default :
  5679.  
  5680.                 break;
  5681.         }
  5682.     }
  5683.  
  5684.     return status;
  5685. }
  5686.  
  5687.  
  5688. ////////////////////////////////////////////////////////////////////////////////
  5689. //
  5690. // PeleFWIMAllocateDMABuildState
  5691. //
  5692. //   This proc allocates a DMA build state record.
  5693. //zzz we really don't need this.  should be allocated by other methods (stack?)
  5694. //
  5695.  
  5696. static OSStatus    PeleFWIMAllocateDMABuildState(
  5697.     PeleFWIMDataPtr                pPeleFWIMData,
  5698.     PeleDMABuildStatePtr        *ppPeleDMABuildState)
  5699. {
  5700.     PeleDMABuildStatePtr        pPeleDMABuildState;
  5701.     OSStatus                    status = noErr;
  5702.     
  5703.     // Allocate memory for record.
  5704.     pPeleDMABuildState =
  5705.         (PeleDMABuildStatePtr) PoolAllocateResident (sizeof (PeleDMABuildState), true);
  5706.     if (pPeleDMABuildState == nil)
  5707.         status = memFullErr;
  5708.  
  5709.     // Return results.
  5710.     if (status == noErr)
  5711.         *ppPeleDMABuildState = pPeleDMABuildState;
  5712.     else
  5713.         *ppPeleDMABuildState = nil;
  5714.  
  5715.     return status;
  5716. }
  5717.  
  5718.  
  5719. ////////////////////////////////////////////////////////////////////////////////
  5720. //
  5721. // PeleFWIMAllocateDMA
  5722. //
  5723. //   This proc allocates a block of consecutive DBDMA descriptors.
  5724. //
  5725.  
  5726. static OSStatus    PeleFWIMAllocateDMA(
  5727.     PeleDMABuildStatePtr        pPeleDMABuildState,
  5728.     PeleDMAPtr                    *ppDMA,
  5729.     PhysicalAddress                *ppDMAPhys,
  5730.     UInt32                        count)
  5731. {
  5732.     PeleDMAPoolDataPtr            pPeleDMAPoolData;
  5733.     PeleDMAPtr                    pDMA,
  5734.                                 dmaPool;
  5735.     UInt32                        dmaPoolPhys;
  5736.     UInt32                        nextFreeDMA;
  5737.     IOPreparationTable            *ioPrep;
  5738.     UInt32                        pageSize, allocSize;
  5739.     Ptr                            p;
  5740.     OSStatus                    status = noErr;
  5741.     
  5742.     // Get pool data record.
  5743.     pPeleDMAPoolData = pPeleDMABuildState->pPeleDMAPoolDataList;
  5744.     
  5745.     // Get PCL pool and next free PCL index.
  5746.     if (pPeleDMAPoolData != nil)
  5747.     {
  5748.         dmaPool = pPeleDMAPoolData->alignedDMAPoolBase;
  5749.         dmaPoolPhys = pPeleDMAPoolData->alignedDMAPoolBasePhys;
  5750.         nextFreeDMA = pPeleDMAPoolData->nextFreeDMA;
  5751.     }
  5752.     else
  5753.     {
  5754.         dmaPool = nil;
  5755.     }
  5756.     
  5757.     // Allocate new pool if current pool is exhausted.
  5758.     // This pool needs to be aligned to the DBDMA size for the compilation logic
  5759.     // to work properly.  Pool size can exceed one phys page as long as we have an
  5760.     // allocator which gives us contiguous pages.
  5761.     
  5762.     // zzz change this to store a freeCount, not a nextFree, so we can compute freeCount
  5763.     // based on the page size & alignment we happen to find.
  5764.     
  5765.     if ((dmaPool == nil) || (nextFreeDMA + count > kDMAPoolSize))
  5766.     {
  5767.         FWDebugStr ((ConstStr255Param) "\p PeleFWIMAllocateDMA - allocating a pool of DBDMA");
  5768.         
  5769.         pageSize = GetLogicalPageSize ();
  5770.         allocSize = sizeof (PeleDMAPoolData) + sizeof (PeleDMA);
  5771.         
  5772.         // Not knowing if MemAllocPhysCont returns page-aligned data, we need to
  5773.         // add one page to align and one more to flush out the end of the struct.
  5774.         // (Could be done more tightly.)
  5775.         
  5776.         allocSize = (allocSize / pageSize) + 3;        // sloppy
  5777.         
  5778.         p = MemAllocatePhysicallyContiguous (allocSize * pageSize, true);
  5779.         if (p != nil)
  5780.         {
  5781.             // Page align
  5782.             pPeleDMAPoolData = (PeleDMAPoolDataPtr)
  5783.                 (((UInt32) p + (pageSize - 1)) & ~(pageSize - 1));
  5784.             
  5785.             // Store original
  5786.             pPeleDMAPoolData->poolAllocatedAddress = (LogicalAddress) p;
  5787.             
  5788.             ioPrep = &pPeleDMAPoolData->ioPrep;
  5789.             
  5790.             // Prepare for IO and get physical address
  5791.             ioPrep->options = kIOLogicalRanges | kIOIsInput | kIOIsOutput;
  5792.             ioPrep->addressSpace = kCurrentAddressSpaceID;            // default
  5793.             ioPrep->granularity = 0;                                // do it all now
  5794.             ioPrep->firstPrepared = 0;
  5795.             ioPrep->mappingEntryCount = allocSize - 1;                // # of pages we will use
  5796.             ioPrep->logicalMapping = 0;
  5797.             ioPrep->physicalMapping = pPeleDMAPoolData->physAddrs;    // return list of phys addrs
  5798.             ioPrep->rangeInfo.range.base = (void *) pPeleDMAPoolData;
  5799.             ioPrep->rangeInfo.range.length = (allocSize - 1) * pageSize;
  5800.             
  5801.             // The CheckpointIO is in PeleFWIMDeallocateDMAPools
  5802.             status = PrepareMemoryForIO (ioPrep);
  5803.             if (status != noErr)
  5804.             {
  5805.                 sprintf (debugStr, "PCL Pool PrepMemIO status %ld    logical %08lx physical %08lx len %lx",
  5806.                          (long) status,
  5807.                          (long) ioPrep->rangeInfo.range.base,
  5808.                          (long) pPeleDMAPoolData->physAddrs[0],
  5809.                          (long) ioPrep->rangeInfo.range.length);
  5810.                 FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  5811.             }
  5812.  
  5813.             pPeleDMAPoolData->pNextPeleDMAPoolData =
  5814.                 pPeleDMABuildState->pPeleDMAPoolDataList;
  5815.             pPeleDMABuildState->pPeleDMAPoolDataList = pPeleDMAPoolData;
  5816.             // Never use dmaPoolDummy.  (This is the only place)  It does not index
  5817.             // the true aligned PCLs.  Use alignedDMAPoolBase as an array instead.
  5818.             pPeleDMAPoolData->alignedDMAPoolBase = (PeleDMAPtr)
  5819.                 (((UInt32) &(pPeleDMAPoolData->dmaPoolDummy[1])) & kDMAAlignmentMask);
  5820.  
  5821.             pPeleDMAPoolData->alignedDMAPoolBasePhys =
  5822.                 (UInt32) pPeleDMAPoolData->physAddrs[0] +
  5823.                 ((UInt32) pPeleDMAPoolData->alignedDMAPoolBase - (UInt32) pPeleDMAPoolData);
  5824.             
  5825.             nextFreeDMA = 0;
  5826.             dmaPool = pPeleDMAPoolData->alignedDMAPoolBase;
  5827.             dmaPoolPhys = pPeleDMAPoolData->alignedDMAPoolBasePhys;
  5828.         }
  5829.         else
  5830.         {
  5831.             status = memFullErr;
  5832.         }
  5833.     }
  5834.     
  5835.     // Allocate PCL from pool.
  5836.     if (status == noErr)
  5837.     {
  5838.         pDMA = &(dmaPool[nextFreeDMA]);
  5839.         nextFreeDMA += count;
  5840.         pPeleDMAPoolData->nextFreeDMA = nextFreeDMA;
  5841.         
  5842. #ifdef PeleVMDebug
  5843.         if (((Ptr) (pDMA)) != ((Ptr) (dmaPoolPhys + (((UInt32) pDMA) - ((UInt32) dmaPool)))))
  5844.         {
  5845.             sprintf (debugStr, "DBDMA alloc logical %08lx != physical %08lx",
  5846.                      (long) pDMA,
  5847.                      (long) (dmaPoolPhys + (((UInt32) pDMA) - ((UInt32) dmaPool))));
  5848.             FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  5849.         }
  5850. #endif
  5851.     }
  5852.  
  5853.     // Return results.
  5854.     if (status == noErr)
  5855.     {
  5856.         *ppDMA = pDMA;
  5857.         *ppDMAPhys = (PhysicalAddress) (dmaPoolPhys + (((UInt32) pDMA) - ((UInt32) dmaPool)));
  5858.     }
  5859.     else
  5860.     {
  5861.         *ppDMA = nil;
  5862.         *ppDMAPhys = nil;
  5863.     }
  5864.  
  5865.     return status;
  5866. }
  5867.  
  5868.  
  5869. ////////////////////////////////////////////////////////////////////////////////
  5870. //
  5871. // PeleFWIMDeallocateDMAPools
  5872. //
  5873. //   This proc deallocates the given list of descriptor pools.
  5874. //
  5875.  
  5876. static void PeleFWIMDeallocateDMAPools(
  5877.     PeleDMAPoolDataPtr            pPeleDMAPoolDataList)
  5878. {
  5879.     PeleDMAPoolDataPtr            pPeleDMAPoolData,
  5880.                                 pNextPeleDMAPoolData;
  5881.     OSStatus                    status = noErr;
  5882.  
  5883.     // Deallocate each pool in list.
  5884.     pPeleDMAPoolData = pPeleDMAPoolDataList;
  5885.     while (pPeleDMAPoolData != nil)
  5886.     {
  5887.         pNextPeleDMAPoolData = pPeleDMAPoolData->pNextPeleDMAPoolData;
  5888.         status = CheckpointIO (pPeleDMAPoolData->ioPrep.preparationID, kNilOptions);
  5889.         if (status != noErr)
  5890.         {
  5891.             sprintf (debugStr, "PCL Pool CheckpointIO status %ld    ID was %08lx",
  5892.                      (long) status,
  5893.                      (long) pNextPeleDMAPoolData->ioPrep.preparationID);
  5894.             FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  5895.         }
  5896.         if (MemDeallocatePhysicallyContiguous (pPeleDMAPoolData->poolAllocatedAddress) != noErr)
  5897.             FWDebugStr ((ConstStr255Param) "\p Dealloc error!!");
  5898.         pPeleDMAPoolData = pNextPeleDMAPoolData;
  5899.     }
  5900. }
  5901.  
  5902.  
  5903. ////////////////////////////////////////////////////////////////////////////////
  5904. //
  5905. // PeleFWIMAllocateIsochPort
  5906. //
  5907. //   This routine will allocate an isochronous channel.
  5908. //zzz must make sure that port is not already in use.
  5909. //zzz should do more error checking.
  5910. //zzz we may need to keep a list of isoch port data records.
  5911. //
  5912.  
  5913. static OSStatus PeleFWIMAllocateIsochPort(
  5914.     FWIMAllocateIsochPortParamsPtr
  5915.                                 pFWIMAllocateIsochPortParams,
  5916.     UInt32                        *pCommandAcceptance)
  5917. {
  5918.     FWIMCommandParamsPtr        pFWIMCommandParams;
  5919.     PeleFWIMDataPtr                pPeleFWIMData;
  5920.     PeleIsochPortDataPtr        pPeleIsochPortData = nil;
  5921.     PeleRegistersPtr            pPeleRegs;
  5922.     PeleDBDMAChannelRegistersPtr
  5923.                                 pDBDMAChannel, pDBDMAChannel2;
  5924.     PeleIsochControlRegistersPtr
  5925.                                 pIsochControl, pIsochControl2;
  5926.     UInt32                        isochChannelNum;
  5927.     UInt32                        dmaChannelNum;
  5928.     Boolean                        talking;
  5929.     OSStatus                    status = noErr;
  5930.  
  5931.     FWDebugStr ((ConstStr255Param) "\pPeleFWIMAllocateIsochPort");
  5932.  
  5933.     // Get our internal data.
  5934.     pFWIMCommandParams = &(pFWIMAllocateIsochPortParams->fwimCommandParams);
  5935.     pPeleFWIMData = (PeleFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  5936.  
  5937.     // Set pending command.
  5938.     pPeleFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMAllocateIsochPortParams;
  5939.     pPeleFWIMData->pendingFWIMCommandStatus = kPelePendingFWIMCommandBusy;
  5940.  
  5941.     // Get base address of Pele registers.
  5942.     pPeleRegs = pPeleFWIMData->pPeleRegisters;
  5943.     
  5944.     // Are we talking?
  5945.     talking = pFWIMAllocateIsochPortParams->talking;
  5946.  
  5947.     if (talking)
  5948.     {
  5949.         pDBDMAChannel = &(pPeleRegs->isochTransmitA);
  5950.         pIsochControl = &(pPeleRegs->itaControl);
  5951.         dmaChannelNum = kIsochTransmitDMA;
  5952.  
  5953.         pDBDMAChannel2 = nil;
  5954.         pIsochControl2 = nil;
  5955.     }
  5956.     else
  5957.     {
  5958.         pDBDMAChannel = &(pPeleRegs->isochReceiveA);
  5959.         pIsochControl = &(pPeleRegs->iraControl);
  5960.         dmaChannelNum = kIsochReceiveDMA;
  5961.  
  5962.         // Pele can only receive one tag (unlike Lynx which receives all tags)
  5963.         // Only tags 0 and 1 are used today, so we'll run both IRDMA contextx,
  5964.         // one for each tag.  Both of them will run, but one will stall at the
  5965.         // first INPUT_LAST because no data will arrive.  This will cause a
  5966.         // problem only if there is a callProc, update, or timeStamp prior to
  5967.         // the first INPUT_LAST, because both DMAs will try to execute it.
  5968.         
  5969.         // Maybe (the plot thickens...) we could advance the "B" DMA starting
  5970.         // point to the first INPUT_LAST before activating the DMAs.  If we
  5971.         // start "A" first then "B", things still happen in order.
  5972.         
  5973.         pDBDMAChannel2 = &(pPeleRegs->isochReceiveB);
  5974.         pIsochControl2 = &(pPeleRegs->irbControl);
  5975.     }
  5976.     
  5977.     // Create an isoch port data record.
  5978.     pPeleIsochPortData =
  5979.         (PeleIsochPortDataPtr) PoolAllocateResident (sizeof (PeleIsochPortData), true);
  5980.     if (pPeleIsochPortData != nil)
  5981.     {
  5982.         pPeleFWIMData->lynxIsochPortDataList[dmaChannelNum] = pPeleIsochPortData;
  5983.         pPeleIsochPortData->originalDCLProgramID =
  5984.             pFWIMAllocateIsochPortParams->dclProgramID;
  5985.         pPeleIsochPortData->translatedDCLProgramID = kInvalidDCLProgramID;
  5986.         pPeleIsochPortData->channelNum = pFWIMAllocateIsochPortParams->channelNum;
  5987.         pPeleIsochPortData->speed = pFWIMAllocateIsochPortParams->speed;
  5988.         pPeleIsochPortData->talking = talking;
  5989.     }
  5990.     else
  5991.     {
  5992.         status = memFullErr;
  5993.     }
  5994.     
  5995.     // Compile a DBDMA program from DCL program.
  5996.     if (status == noErr)
  5997.     {
  5998.         // Check if DBDMA program must be translated.
  5999.         if (PeleFWIMIsCompilableDCLProgram (pPeleIsochPortData->originalDCLProgramID))
  6000.         {
  6001.             pPeleIsochPortData->dclProgramID = pPeleIsochPortData->originalDCLProgramID;
  6002.         }
  6003.         else
  6004.         {
  6005.             //zzz need to be able to deallocate this.
  6006.             status = FWTranslateDCLProgram (pPeleIsochPortData->originalDCLProgramID,
  6007.                                             &(pPeleIsochPortData->translatedDCLProgramID));
  6008.             if (status == noErr)
  6009.             {
  6010.                 pPeleIsochPortData->dclProgramID =
  6011.                     pPeleIsochPortData->translatedDCLProgramID;
  6012.             }
  6013.         }
  6014.         
  6015.         // Compile the DCL program.
  6016.         if (status == noErr)
  6017.         {
  6018.             status = PeleFWIMCompileDCLProgram
  6019.                         (pPeleFWIMData,
  6020.                          pPeleIsochPortData->dclProgramID,
  6021.                          dmaChannelNum,
  6022.                          pPeleIsochPortData->channelNum,
  6023.                          pPeleIsochPortData->speed);
  6024.         }
  6025.  
  6026.         // Set start, stop, and release procedures for DCL program.
  6027.         if (status == noErr)
  6028.         {
  6029.             if (talking)
  6030.             {
  6031.                 FWSetDCLProgramStartProc (pPeleIsochPortData->dclProgramID,
  6032.                                           PeleFWIMStartTalkingDCLProgram);
  6033.                 FWSetDCLProgramStopProc (pPeleIsochPortData->dclProgramID,
  6034.                                          PeleFWIMStopTalkingDCLProgram);
  6035.                 FWSetDCLProgramReleaseProc (pPeleIsochPortData->dclProgramID,
  6036.                                             PeleFWIMReleaseDCLProgram);
  6037.             }
  6038.             else
  6039.             {
  6040.                 FWSetDCLProgramStartProc (pPeleIsochPortData->dclProgramID,
  6041.                                           PeleFWIMStartListeningDCLProgram);
  6042.                 FWSetDCLProgramStopProc (pPeleIsochPortData->dclProgramID,
  6043.                                          PeleFWIMStopListeningDCLProgram);
  6044.                 FWSetDCLProgramReleaseProc (pPeleIsochPortData->dclProgramID,
  6045.                                             PeleFWIMReleaseDCLProgram);
  6046.             }
  6047.         }
  6048.     }
  6049.  
  6050.     // Set up appropriate DMA channel.
  6051.     if (status == noErr)
  6052.     {
  6053.         // Quiet the DMA channel.
  6054.         pDBDMAChannel->channelControl = EndianSwapImm32Bit (kPeleClrAll);
  6055.         SynchronizeIO ();
  6056.         
  6057.         if (pDBDMAChannel2)
  6058.         {
  6059.             pDBDMAChannel2->channelControl = EndianSwapImm32Bit (kPeleClrAll);
  6060.             SynchronizeIO ();
  6061.         }
  6062.         
  6063.         isochChannelNum = pPeleIsochPortData->channelNum;
  6064.  
  6065.         // Set channel to transmit on if we're talking.
  6066.         if (talking)
  6067.         {            
  6068.             // zzz This will transmit at s100 rate.  Lynx sample code does the same.
  6069.             pIsochControl->configuration =
  6070.                 EndianSwap32Bit ((isochChannelNum << kPeleITDMAconfigChannelPhase) |
  6071.                                  kPeleITDMAconfigRateMode);
  6072.             SynchronizeIO ();
  6073.         }
  6074.  
  6075.         // Set up comparators to receive on this port's channel.
  6076.         if (!talking)
  6077.         {
  6078.             // BufferMode means one packet per INPUT_LAST, according to the spec.
  6079.             
  6080.             // This clears the startOnEvent.  Later, we may set it to 11 to force
  6081.             // a start, depending on a compile option.  Either way, we should instead
  6082.             // set it to 01 (start on cycle) if we are so requested, but we don't. zzz
  6083.             
  6084.             // Receive tag 0 on IRA
  6085.             pIsochControl->configuration =
  6086.                 EndianSwap32Bit (kPeleIRDMAconfigBufferMode |
  6087.                                  (0 << kPeleIRDMAconfigTagPhase) |
  6088.                                  (isochChannelNum << kPeleIRDMAconfigChannelPhase));
  6089.             SynchronizeIO ();
  6090.             
  6091.             if (pIsochControl2)
  6092.             {
  6093.                 // Receive tag 1 on IRB
  6094.                 pIsochControl2->configuration =
  6095.                     EndianSwap32Bit (kPeleIRDMAconfigBufferMode |
  6096.                                      (1 << kPeleIRDMAconfigTagPhase) |
  6097.                                      (isochChannelNum << kPeleIRDMAconfigChannelPhase));
  6098.                 SynchronizeIO ();
  6099.             }
  6100.         }
  6101.  
  6102.         // Set our data for port.
  6103.         pFWIMAllocateIsochPortParams->fwimIsochPortCommandParams.fwimIsochPortData =
  6104.             (UInt32) pPeleIsochPortData;
  6105.     }
  6106.  
  6107.     // Clean up on error.
  6108.     if (status != noErr)
  6109.     {
  6110.         if (pPeleIsochPortData != nil)
  6111.             _PeleFWIMReleaseIsochPort (pPeleFWIMData, pPeleIsochPortData);
  6112.     }
  6113.  
  6114.     // Complete FWIM command.
  6115.     pPeleFWIMData->pPendingFWIMCommand = nil;
  6116.     status = FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
  6117.  
  6118.     // Return command acceptance.
  6119.     //zzz what if we call FWIMCommandIsComplete before returning this???
  6120.     //zzz well, it still works, but will it always?
  6121.     //zzz actually, when we switch to the dispatch table, each routine can return
  6122.     //zzz the appropriate acceptance, so don't worry about it for now.
  6123.     *pCommandAcceptance = kFWIMCommandAcceptNoMore;
  6124.  
  6125.     return status;
  6126. }
  6127.  
  6128.  
  6129. ////////////////////////////////////////////////////////////////////////////////
  6130. //
  6131. // PeleFWIMReleaseIsochPort
  6132. //
  6133. //   This routine will release resources allocated for the given isochronous
  6134. // channel.
  6135. //
  6136.  
  6137. static OSStatus PeleFWIMReleaseIsochPort(
  6138.     FWIMReleaseIsochPortParamsPtr
  6139.                                 pFWIMReleaseIsochPortParams,
  6140.     UInt32                        *pCommandAcceptance)
  6141. {
  6142.     FWIMCommandParamsPtr        pFWIMCommandParams;
  6143.     PeleFWIMDataPtr                pPeleFWIMData;
  6144.     PeleIsochPortDataPtr        pPeleIsochPortData;
  6145.     OSStatus                    status = noErr;
  6146.  
  6147.     FWDebugStr ((ConstStr255Param) "\pPeleFWIMReleaseIsochPort");
  6148.  
  6149.     // Get our internal data.
  6150.     pFWIMCommandParams = &(pFWIMReleaseIsochPortParams->fwimCommandParams);
  6151.     pPeleFWIMData = (PeleFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  6152.  
  6153.     // Set pending command.
  6154.     pPeleFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMReleaseIsochPortParams;
  6155.     pPeleFWIMData->pendingFWIMCommandStatus = kPelePendingFWIMCommandBusy;
  6156.  
  6157.     // Get isoch port data.
  6158.     pPeleIsochPortData = (PeleIsochPortDataPtr)
  6159.         pFWIMReleaseIsochPortParams->fwimIsochPortCommandParams.fwimIsochPortData;
  6160.  
  6161.     // Release resources for isoch port.
  6162.     if (pPeleIsochPortData != nil)
  6163.         status = _PeleFWIMReleaseIsochPort (pPeleFWIMData, pPeleIsochPortData);
  6164.  
  6165.     // Complete FWIM command.
  6166.     pPeleFWIMData->pPendingFWIMCommand = nil;
  6167.     status = FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
  6168.  
  6169.     // Return command acceptance.
  6170.     //zzz what if we call FWIMCommandIsComplete before returning this???
  6171.     //zzz well, it still works, but will it always?
  6172.     //zzz actually, when we switch to the dispatch table, each routine can return
  6173.     //zzz the appropriate acceptance, so don't worry about it for now.
  6174.     *pCommandAcceptance = kFWIMCommandAcceptNoMore;
  6175.  
  6176.     return status;
  6177. }
  6178.  
  6179.  
  6180. ////////////////////////////////////////////////////////////////////////////////
  6181. //
  6182. // _PeleFWIMReleaseIsochPort
  6183. //
  6184. //   This routine will release resources allocated for the given isochronous
  6185. // channel.
  6186. //
  6187.  
  6188. static OSStatus _PeleFWIMReleaseIsochPort(
  6189.     PeleFWIMDataPtr                pPeleFWIMData,
  6190.     PeleIsochPortDataPtr        pPeleIsochPortData)
  6191. {
  6192.     PeleDCLCompilerEngineDataPtr
  6193.                                 pPeleDCLCompilerEngineData = nil;
  6194.     OSStatus                    status = noErr;
  6195.  
  6196.     // Release DCL resources.
  6197.     if (pPeleIsochPortData->originalDCLProgramID != kInvalidDCLProgramID)
  6198.         status = FWReleaseDCLProgram (pPeleIsochPortData->originalDCLProgramID);
  6199.     
  6200.     // Deallocate isoch port data record.
  6201.     PoolDeallocate ((Ptr) pPeleIsochPortData);
  6202.     
  6203.     return status;
  6204. }
  6205.  
  6206.  
  6207. ////////////////////////////////////////////////////////////////////////////////
  6208. //
  6209. // PeleFWIMStartIsochPort
  6210. //
  6211. //   Start up the given isochronous port on the given sync event using the
  6212. // given buffer.
  6213. //
  6214.  
  6215. static OSStatus PeleFWIMStartIsochPort(
  6216.     FWIMIsochPortControlParamsPtr
  6217.                                 pFWIMIsochPortControlParams,
  6218.     UInt32                        *pCommandAcceptance)
  6219. {
  6220.     FWIMCommandParamsPtr        pFWIMCommandParams;
  6221.     PeleFWIMDataPtr                pPeleFWIMData;
  6222.     PeleIsochPortDataPtr        pPeleIsochPortData;
  6223.     OSStatus                    status = noErr;
  6224.  
  6225.     FWDebugStr ((ConstStr255Param) "\pPeleFWIMStartIsochPort");
  6226.  
  6227.     // Get our internal data.
  6228.     pFWIMCommandParams = &(pFWIMIsochPortControlParams->fwimCommandParams);
  6229.     pPeleFWIMData = (PeleFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  6230.  
  6231.     // Set pending command.
  6232.     pPeleFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMIsochPortControlParams;
  6233.     pPeleFWIMData->pendingFWIMCommandStatus = kPelePendingFWIMCommandBusy;
  6234.  
  6235.     // Get isoch port data.
  6236.     pPeleIsochPortData = (PeleIsochPortDataPtr)
  6237.         pFWIMIsochPortControlParams->fwimIsochPortCommandParams.fwimIsochPortData;
  6238.  
  6239.     // Start DCL program.
  6240.     if (status == noErr)
  6241.         status = FWStartDCLProgram (pPeleIsochPortData->originalDCLProgramID);
  6242.  
  6243.     // Finish up command.
  6244.     pPeleFWIMData->pPendingFWIMCommand = nil;
  6245.     status = FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
  6246.  
  6247.     // Return command acceptance.
  6248.     //zzz what if we call FWIMCommandIsComplete before returning this???
  6249.     //zzz well, it still works, but will it always?
  6250.     //zzz actually, when we switch to the dispatch table, each routine can return
  6251.     //zzz the appropriate acceptance, so don't worry about it for now.
  6252.     *pCommandAcceptance = kFWIMCommandAcceptNoMore;
  6253.  
  6254.     return status;
  6255. }
  6256.  
  6257.  
  6258. ////////////////////////////////////////////////////////////////////////////////
  6259. //
  6260. // PeleFWIMStopIsochPort
  6261. //
  6262. //   Stop the given isochronous port on the given sync event.
  6263. //
  6264.  
  6265. static OSStatus PeleFWIMStopIsochPort(
  6266.     FWIMIsochPortControlParamsPtr
  6267.                                 pFWIMIsochPortControlParams,
  6268.     UInt32                        *pCommandAcceptance)
  6269. {
  6270.     FWIMCommandParamsPtr        pFWIMCommandParams;
  6271.     PeleFWIMDataPtr                pPeleFWIMData;
  6272.     PeleIsochPortDataPtr        pPeleIsochPortData;
  6273.     OSStatus                    status = noErr;
  6274.  
  6275.     FWDebugStr ((ConstStr255Param) "\pPeleFWIMStopIsochPort");
  6276.  
  6277.     // Get our internal data.
  6278.     pFWIMCommandParams = &(pFWIMIsochPortControlParams->fwimCommandParams);
  6279.     pPeleFWIMData = (PeleFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  6280.  
  6281.     // Set pending command.
  6282.     pPeleFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMIsochPortControlParams;
  6283.     pPeleFWIMData->pendingFWIMCommandStatus = kPelePendingFWIMCommandBusy;
  6284.  
  6285.     // Get isoch port data.
  6286.     pPeleIsochPortData = (PeleIsochPortDataPtr)
  6287.         pFWIMIsochPortControlParams->fwimIsochPortCommandParams.fwimIsochPortData;
  6288.  
  6289.     // Stop DCL program.
  6290.     if (status == noErr)
  6291.         status = FWStopDCLProgram (pPeleIsochPortData->originalDCLProgramID);
  6292.  
  6293.     // Finish up command.
  6294.     pPeleFWIMData->pPendingFWIMCommand = nil;
  6295.     status = FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
  6296.  
  6297.     // Return command acceptance.
  6298.     //zzz what if we call FWIMCommandIsComplete before returning this???
  6299.     //zzz well, it still works, but will it always?
  6300.     //zzz actually, when we switch to the dispatch table, each routine can return
  6301.     //zzz the appropriate acceptance, so don't worry about it for now.
  6302.     *pCommandAcceptance = kFWIMCommandAcceptNoMore;
  6303.  
  6304.     return status;
  6305. }
  6306.  
  6307.  
  6308. ////////////////////////////////////////////////////////////////////////////////
  6309. //
  6310. // PeleFWIMStartTalkingDCLProgram
  6311. //
  6312. //   This routine starts running the given DCL program.
  6313. //
  6314.  
  6315. static OSStatus PeleFWIMStartTalkingDCLProgram(
  6316.     DCLProgramID                dclProgramID)
  6317. {
  6318.     PeleDCLCompilerEngineDataPtr
  6319.                                 pPeleDCLCompilerEngineData;
  6320.     PeleFWIMDataPtr                pPeleFWIMData;
  6321.     PeleRegistersPtr            pPeleRegs;
  6322.     UInt32                        eventCycle;
  6323.     OSStatus                    status = noErr;
  6324.  
  6325.     FWDebugStr ((ConstStr255Param) "\p PeleFWIMStartTalkingDCLProgram");
  6326.     
  6327.     // Get our engine data and FWIM data.
  6328.     status = FWGetDCLProgramEngineData
  6329.                 (dclProgramID, (UInt32 *) &pPeleDCLCompilerEngineData);
  6330.     if (status == noErr)
  6331.         pPeleFWIMData = pPeleDCLCompilerEngineData->pPeleFWIMData;
  6332.  
  6333.     // Get base address of Pele registers.
  6334.     if (status == noErr)
  6335.         pPeleRegs = pPeleFWIMData->pPeleRegisters;
  6336.  
  6337.     // Start the DMA engine.
  6338.     if (status == noErr)
  6339.     {
  6340.         // We'll report statistics at the end of the transmit, if FireBug enabled.
  6341. //        pPeleRegs->fifoOverUnderErrorCounters = EndianSwapImm32Bit (0);
  6342.         
  6343.         // Load a physical address (already known)
  6344.         pPeleRegs->isochTransmitA.commandPtr =
  6345.             EndianSwap32Bit ((UInt32) pPeleDCLCompilerEngineData->pStartDMA);
  6346.         SynchronizeIO ();
  6347.  
  6348.         // zzz We should satisfy the start condition of the DCL program.
  6349.         // But for now, the only known DCL program is DV transmit, and it will work
  6350.         // as long as we start on a cycle number whose low 4 bits are zero.
  6351.         
  6352.         pPeleRegs->itaControl.configuration |=
  6353.             EndianSwapImm32Bit (kPeleEventCycleNumber << kPeleITDMAconfigStartOnEventPhase);
  6354.         SynchronizeIO ();
  6355.         
  6356.         eventCycle = EndianSwap32Bit (pPeleRegs->isochronousCycleTimer);
  6357.         
  6358.         // Add 50 cycles.  If that would give us a cycle number > 7999, wrap around
  6359.         
  6360.         if (((eventCycle & kPeleICTCount) >> kPeleICTCountPhase) > 7949)
  6361.             eventCycle += (193 << kPeleICTCountPhase);
  6362.             
  6363.         eventCycle += (50 << kPeleICTCountPhase);
  6364.         
  6365.         // Make sure low 4 bits are zero
  6366.         
  6367.         eventCycle = (eventCycle >> (kPeleICTCountPhase + 4)) << (kPeleICTCountPhase + 4);
  6368.         
  6369.         pPeleRegs->itaControl.eventCycle = EndianSwap32Bit (eventCycle);
  6370.         SynchronizeIO ();
  6371.         
  6372.         // Start DMA.
  6373.         pPeleRegs->isochTransmitA.channelControl = EndianSwapImm32Bit (kPeleSetRun);
  6374.         SynchronizeIO ();
  6375.     }
  6376.  
  6377.     return status;
  6378. }
  6379.  
  6380.  
  6381. ////////////////////////////////////////////////////////////////////////////////
  6382. //
  6383. // PeleFWIMStartListeningDCLProgram
  6384. //
  6385. //   This routine starts running the given DCL program.
  6386. //
  6387.  
  6388. static OSStatus PeleFWIMStartListeningDCLProgram(
  6389.     DCLProgramID                dclProgramID)
  6390. {
  6391.     PeleDCLCompilerEngineDataPtr
  6392.                                 pPeleDCLCompilerEngineData;
  6393.     PeleFWIMDataPtr                pPeleFWIMData;
  6394.     PeleRegistersPtr            pPeleRegs;
  6395.     OSStatus                    status = noErr;
  6396.  
  6397.     FWDebugStr ((ConstStr255Param) "\p PeleFWIMStartListeningDCLProgram");
  6398.  
  6399.     // Get our engine data and FWIM data.
  6400.     status = FWGetDCLProgramEngineData
  6401.                 (dclProgramID, (UInt32 *) &pPeleDCLCompilerEngineData);
  6402.     if (status == noErr)
  6403.         pPeleFWIMData = pPeleDCLCompilerEngineData->pPeleFWIMData;
  6404.  
  6405.     // Get base address of Pele registers.
  6406.     if (status == noErr)
  6407.         pPeleRegs = pPeleFWIMData->pPeleRegisters;
  6408.  
  6409.     // Start the DMA engine.
  6410.     if (status == noErr)
  6411.     {
  6412.         // Load a physical address for tag 0 program
  6413.         pPeleRegs->isochReceiveA.commandPtr =
  6414.             EndianSwap32Bit ((UInt32) pPeleDCLCompilerEngineData->pStartDMA);
  6415.         SynchronizeIO ();
  6416.  
  6417.         //zzz might be a good idea to advance the tag 1 program to the first INPUT_LAST
  6418.         // so we don't double up any callprocs, timestamps, updates, etc.
  6419.         
  6420.         // Load a physical address for tag 1 program
  6421.         pPeleRegs->isochReceiveB.commandPtr =
  6422.             EndianSwap32Bit ((UInt32) pPeleDCLCompilerEngineData->pStartDMA);
  6423.         SynchronizeIO ();
  6424.  
  6425.         //zzz Note, we are supposed to honor start-on-cycle requests (see the compiler).
  6426.         // But the sample code all works if we just start immediately.
  6427.         
  6428. #ifdef PELE_NO_START_ON_RUN
  6429.         // Some Pele parts can't just start on event 00, they require a cycle-match.
  6430.         // Actually, the DMA will run, but no data enters the FIFO, so nothing happens.
  6431.         // But setting the event to 11 will make Pele think it already started:
  6432.         
  6433.         pPeleRegs->iraControl.configuration |=
  6434.             EndianSwapImm32Bit (kPeleEventOccured << kPeleIRDMAconfigStartOnEventPhase);
  6435.         SynchronizeIO ();
  6436.         
  6437.         pPeleRegs->irbControl.configuration |=
  6438.             EndianSwapImm32Bit (kPeleEventOccured << kPeleIRDMAconfigStartOnEventPhase);
  6439.         SynchronizeIO ();
  6440. #endif
  6441.  
  6442.         // Start DMA.
  6443.         pPeleRegs->isochReceiveA.channelControl = EndianSwapImm32Bit (kPeleSetRun);
  6444.         SynchronizeIO ();
  6445.  
  6446.         // Start DMA.
  6447.         pPeleRegs->isochReceiveB.channelControl = EndianSwapImm32Bit (kPeleSetRun);
  6448.         SynchronizeIO ();
  6449.     }
  6450.  
  6451.     return status;
  6452. }
  6453.  
  6454.  
  6455. ////////////////////////////////////////////////////////////////////////////////
  6456. //
  6457. // PeleFWIMStopTalkingDCLProgram
  6458. //
  6459. //   This routine stops running the given DCL program.
  6460. //
  6461.  
  6462. static OSStatus PeleFWIMStopTalkingDCLProgram(
  6463.     DCLProgramID                dclProgramID)
  6464. {
  6465.     PeleDCLCompilerEngineDataPtr
  6466.                                 pPeleDCLCompilerEngineData;
  6467.     PeleFWIMDataPtr                pPeleFWIMData;
  6468.     PeleRegistersPtr            pPeleRegs;
  6469.     OSStatus                    status = noErr;
  6470.  
  6471.     FWDebugStr ((ConstStr255Param) "\p PeleFWIMStopTalkingDCLProgram");
  6472.  
  6473.     // Get our engine data and FWIM data.
  6474.     status = FWGetDCLProgramEngineData
  6475.                 (dclProgramID, (UInt32 *) &pPeleDCLCompilerEngineData);
  6476.     if (status == noErr)
  6477.         pPeleFWIMData = pPeleDCLCompilerEngineData->pPeleFWIMData;
  6478.  
  6479.     // Get base address of Pele registers.
  6480.     if (status == noErr)
  6481.         pPeleRegs = pPeleFWIMData->pPeleRegisters;
  6482.  
  6483.     // Stop the DMA engine.
  6484.     if (status == noErr)
  6485.     {
  6486.         // Stop the DMA.
  6487.         // zzzCould be more graceful, not send partial packet?
  6488.         pPeleRegs->isochTransmitA.channelControl = EndianSwapImm32Bit (kPeleClrAll);
  6489.         SynchronizeIO ();
  6490.                 
  6491. #ifdef PeleFireBug
  6492. {
  6493.     UInt32 temp = EndianSwap32Bit (pPeleRegs->fifoOverUnderErrorCounters);
  6494.     sprintf (fireBug, "PeleFWIM:  FIFO stats during iso tx:  ITF_UNDER %ld,  ATF_UNDER %ld,  GRF_OVER %ld",
  6495.              (temp >> 16) & 0xff, (temp >> 8) & 0xff, temp & 0xff);
  6496.     PeleFWIMFireBugMsg (pPeleFWIMData, fireBug);
  6497. }
  6498. #endif
  6499.     }
  6500.  
  6501.     return status;
  6502. }
  6503.  
  6504.  
  6505. ////////////////////////////////////////////////////////////////////////////////
  6506. //
  6507. // PeleFWIMStopListeningDCLProgram
  6508. //
  6509. //   This routine stops running the given DCL program.
  6510. //
  6511.  
  6512. static OSStatus PeleFWIMStopListeningDCLProgram(
  6513.     DCLProgramID                dclProgramID)
  6514. {
  6515.     PeleDCLCompilerEngineDataPtr
  6516.                                 pPeleDCLCompilerEngineData;
  6517.     PeleFWIMDataPtr                pPeleFWIMData;
  6518.     PeleRegistersPtr            pPeleRegs;
  6519.     OSStatus                    status = noErr;
  6520.  
  6521.     FWDebugStr ((ConstStr255Param) "\p PeleFWIMStopListeningDCLProgram");
  6522.  
  6523.     // Get our engine data and FWIM data.
  6524.     status = FWGetDCLProgramEngineData
  6525.                 (dclProgramID, (UInt32 *) &pPeleDCLCompilerEngineData);
  6526.     if (status == noErr)
  6527.         pPeleFWIMData = pPeleDCLCompilerEngineData->pPeleFWIMData;
  6528.  
  6529.     // Get base address of Pele registers.
  6530.     if (status == noErr)
  6531.         pPeleRegs = pPeleFWIMData->pPeleRegisters;
  6532.  
  6533.     // Stop the DMA engine.
  6534.     if (status == noErr)
  6535.     {
  6536.         // Stop the DMA - zzz could be more graceful, not stop mid-packet.
  6537.         //zzz need way to bit bucket any remaining packets in FIFO
  6538.  
  6539.         pPeleRegs->isochReceiveA.channelControl = EndianSwapImm32Bit (kPeleClrAll);
  6540.         SynchronizeIO ();
  6541.  
  6542.         pPeleRegs->isochReceiveB.channelControl = EndianSwapImm32Bit (kPeleClrAll);
  6543.         SynchronizeIO ();
  6544.     }
  6545.  
  6546.     return status;
  6547. }
  6548.  
  6549.  
  6550. ////////////////////////////////////////////////////////////////////////////////
  6551. //
  6552. // PeleFWIMReleaseDCLProgram
  6553. //
  6554. //   This routine releases the resources allocated for the given DCL program.
  6555. //
  6556.  
  6557. static OSStatus PeleFWIMReleaseDCLProgram(
  6558.     DCLProgramID                dclProgramID)
  6559. {
  6560.     PeleDCLCompilerEngineDataPtr
  6561.                                 pPeleDCLCompilerEngineData;
  6562.     PeleFWIMDataPtr                pPeleFWIMData;
  6563.     OSStatus                    status = noErr;
  6564.  
  6565.     FWDebugStr ((ConstStr255Param) "\p PeleFWIMReleaseDCLProgram");
  6566.  
  6567.     // Get our engine data and FWIM data.
  6568.     status = FWGetDCLProgramEngineData
  6569.                 (dclProgramID, (UInt32 *) &pPeleDCLCompilerEngineData);
  6570.     if (status == noErr)
  6571.         pPeleFWIMData = pPeleDCLCompilerEngineData->pPeleFWIMData;
  6572.  
  6573.     if (status == noErr)
  6574.     {
  6575.         // Deallocate PCL pools.
  6576.         if (pPeleDCLCompilerEngineData->pPeleDMAPoolDataList != nil)
  6577.         {
  6578.             PeleFWIMDeallocateDMAPools
  6579.                 (pPeleDCLCompilerEngineData->pPeleDMAPoolDataList);
  6580.         }
  6581.         
  6582.         // Release all VM resources
  6583.         // Kind of a hack - we set this to -1 if the PrepareMemoryForIO failed:
  6584.         if (pPeleDCLCompilerEngineData->ioPrep.mappingEntryCount != -1)
  6585.         {
  6586.             status = CheckpointIO (pPeleDCLCompilerEngineData->ioPrep.preparationID, kNilOptions);
  6587.             if (status != noErr)
  6588.             {
  6589.                 sprintf (debugStr, "DCL data CheckpointIO status %ld",
  6590.                          (long) status);
  6591.                 FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  6592.             }
  6593.             PoolDeallocate ((Ptr) pPeleDCLCompilerEngineData->ioPrep.rangeInfo.multipleRanges.rangeTable);
  6594.             PoolDeallocate ((Ptr) pPeleDCLCompilerEngineData->ioPrep.physicalMapping);
  6595.         }
  6596.         
  6597.         // Deallocate compiler data list for DCLs
  6598.         if (pPeleDCLCompilerEngineData->pPeleDCLCompilerDCLData != nil)
  6599.             PoolDeallocate ((Ptr) pPeleDCLCompilerEngineData->pPeleDCLCompilerDCLData);
  6600.             
  6601.         // Deallocate engine data.
  6602.         PoolDeallocate ((Ptr) pPeleDCLCompilerEngineData);
  6603.     }
  6604.     
  6605.     return status;
  6606. }
  6607.  
  6608.  
  6609. ////////////////////////////////////////////////////////////////////////////////
  6610. //
  6611. // PeleFWIMReadRequestTimeoutHandler
  6612. //
  6613. //   This proc will retry a transaction if any more retries are specified.
  6614. //
  6615.  
  6616. static OSStatus    PeleFWIMReadRequestTimeoutHandler(
  6617.     void                        *p1,
  6618.     void                        *p2)
  6619. {
  6620.     FWIMCommandParamsPtr        pFWIMCommandParams;
  6621.     FWIMAsynchCommandParamsPtr    pFWIMAsynchCommandParams =
  6622.                                     (FWIMAsynchCommandParamsPtr) p1;
  6623.     PeleFWIMDataPtr                pPeleFWIMData; 
  6624.     UInt32                        commandAcceptance;
  6625.     Boolean                        commandBusy;
  6626.     OSStatus                    pendingFWIMCommandStatus,
  6627.                                 status = noErr;
  6628.  
  6629. //    FWDebugStr ((ConstStr255Param) "\pPeleFWIMReadRequestTimeoutHandler");
  6630.  
  6631.     // Get our internal data.
  6632.     pFWIMCommandParams = &(pFWIMAsynchCommandParams->fwimCommandParams);
  6633.     pPeleFWIMData = (PeleFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  6634.     pendingFWIMCommandStatus = pPeleFWIMData->pendingFWIMCommandStatus;
  6635.  
  6636.     // Note that timer went off.
  6637.     pPeleFWIMData->requestTimeoutTimerSet = false;
  6638.  
  6639.     // Check if command is still busy.
  6640.     if (pendingFWIMCommandStatus == kPelePendingFWIMCommandBusy)
  6641.     {
  6642.         commandBusy = true;
  6643.     }
  6644.     else
  6645.     {
  6646.         commandBusy = false;
  6647.         status = pendingFWIMCommandStatus;
  6648.     }
  6649.  
  6650.     // Retry if there are more retries left, otherwise return with timeout
  6651.     // status.
  6652.     if (commandBusy)
  6653.     {
  6654.         if (((SInt8) pFWIMAsynchCommandParams->numRetries--) > 0)
  6655.         {
  6656.             status = PeleFWIMRead (pFWIMAsynchCommandParams, &commandAcceptance);//zzz shouldn't have to pass in commandAcceptance
  6657.         }
  6658.         else
  6659.         {
  6660.             status = timeoutErr;
  6661.         }
  6662.  
  6663.         if (status != noErr)
  6664.             commandBusy = false;
  6665.     }
  6666.  
  6667.     // Complete command if it's no longer busy.
  6668.     if (!commandBusy)
  6669.     {
  6670.         pPeleFWIMData->pPendingFWIMCommand = nil;
  6671.         status = FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
  6672.     }
  6673.  
  6674.     return status;
  6675. }
  6676.  
  6677.  
  6678. ////////////////////////////////////////////////////////////////////////////////
  6679. //
  6680. // PeleFWIMWriteRequestTimeoutHandler
  6681. //
  6682. //   This proc will retry a transaction if any more retries are specified.
  6683. //zzz Only need this until reset code completes commands manually.
  6684. //zzz need locking mechanism between this routine and the ack int routine.
  6685. //
  6686. // Note - presently unused (not set in PeleFWIMWrite)
  6687.  
  6688. static OSStatus    PeleFWIMWriteRequestTimeoutHandler(
  6689.     void                        *p1,
  6690.     void                        *p2)
  6691. {
  6692.     FWIMCommandParamsPtr        pFWIMCommandParams;
  6693.     FWIMAsynchCommandParamsPtr    pFWIMAsynchCommandParams =
  6694.                                     (FWIMAsynchCommandParamsPtr) p1;
  6695.     PeleFWIMDataPtr                pPeleFWIMData; 
  6696.     PeleRegistersPtr            pPeleRegs;
  6697.     Boolean                        commandBusy;
  6698.     OSStatus                    pendingFWIMCommandStatus,
  6699.                                 status = noErr;
  6700.  
  6701. //    FWDebugStr ((ConstStr255Param) "\pPeleFWIMWriteRequestTimeoutHandler");
  6702.  
  6703.     // Get our internal data.
  6704.     pFWIMCommandParams = &(pFWIMAsynchCommandParams->fwimCommandParams);
  6705.     pPeleFWIMData = (PeleFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  6706.     pendingFWIMCommandStatus = pPeleFWIMData->pendingFWIMCommandStatus;
  6707.     pPeleRegs = pPeleFWIMData->pPeleRegisters;
  6708.  
  6709.     // Note that timer went off.
  6710.     pPeleFWIMData->requestTimeoutTimerSet = false;
  6711.  
  6712.     // Check if command is still busy.
  6713.     if (pendingFWIMCommandStatus == kPelePendingFWIMCommandBusy)
  6714.     {
  6715.         commandBusy = true;
  6716.     }
  6717.     else
  6718.     {
  6719.         commandBusy = false;
  6720.         status = pendingFWIMCommandStatus;
  6721.     }
  6722.  
  6723.     // Check if ack code indicates a completed transfer.  Retry if it doesn't.
  6724.     if (commandBusy)
  6725.     {
  6726. // NYI
  6727. // Works differently in Pele - look in DMA/PCL status
  6728.         FWDebugStr ((ConstStr255Param) "\pPeleFWIMWriteRequestTimeoutHandler - NYI ###");
  6729. #if 0
  6730.         nodeAddress = EndianSwap32Bit (pLinkRegs->nodeAddress);
  6731.         ackCode =
  6732.             (nodeAddress & kTINodeAddressATAck) >> kTINodeAddressATAckPhase;
  6733.         if (ackCode == kFWAckComplete)
  6734.         {
  6735.             commandBusy = false;
  6736.             status = noErr;
  6737.         }
  6738.         else
  6739.         {
  6740.             if (((SInt8) pFWIMAsynchCommandParams->numRetries--) > 0)
  6741.             {
  6742.                 status = PeleFWIMWrite (pFWIMAsynchCommandParams, &commandAcceptance);//zzz shouldn't have to pass in commandAcceptance
  6743.             }
  6744.             else
  6745.             {
  6746.                 status = timeoutErr;
  6747.             }
  6748.  
  6749.             if (status != noErr)
  6750.                 commandBusy = false;
  6751.         }
  6752. #endif
  6753.     }
  6754.  
  6755.     // Complete command if it's no longer busy.
  6756.     if (!commandBusy)
  6757.     {
  6758.         pPeleFWIMData->pPendingFWIMCommand = nil;
  6759.         status =
  6760.             FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
  6761.     }
  6762.  
  6763.     return status;
  6764. }
  6765.  
  6766.  
  6767. ////////////////////////////////////////////////////////////////////////////////
  6768. //
  6769. // PeleFWIMLockRequestTimeoutHandler
  6770. //
  6771. //   This proc will retry a transaction if any more retries are specified.
  6772. //zzz need to check if command is still busy.
  6773. // NYI - Never tested for Pele
  6774. //
  6775.  
  6776. static OSStatus    PeleFWIMLockRequestTimeoutHandler(
  6777.     void                        *p1,
  6778.     void                        *p2)
  6779. {
  6780.     FWIMCommandParamsPtr        pFWIMCommandParams;
  6781.     FWIMAsynchCommandParamsPtr    pFWIMAsynchCommandParams =
  6782.                                     (FWIMAsynchCommandParamsPtr) p1;
  6783.     PeleFWIMDataPtr                pPeleFWIMData; 
  6784.     UInt32                        commandAcceptance;
  6785.     Boolean                        commandBusy;
  6786.     OSStatus                    pendingFWIMCommandStatus,
  6787.                                 status = noErr;
  6788.  
  6789. //    FWDebugStr ((ConstStr255Param) "\pPeleFWIMLockRequestTimeoutHandler");
  6790.  
  6791.     // Get our internal data.
  6792.     pFWIMCommandParams = &(pFWIMAsynchCommandParams->fwimCommandParams);
  6793.     pPeleFWIMData = (PeleFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  6794.     pendingFWIMCommandStatus = pPeleFWIMData->pendingFWIMCommandStatus;
  6795.  
  6796.     // Note that timer went off.
  6797.     pPeleFWIMData->requestTimeoutTimerSet = false;
  6798.  
  6799.     // Check if command is still busy.
  6800.     if (pendingFWIMCommandStatus == kPelePendingFWIMCommandBusy)
  6801.     {
  6802.         commandBusy = true;
  6803.     }
  6804.     else
  6805.     {
  6806.         commandBusy = false;
  6807.         status = pendingFWIMCommandStatus;
  6808.     }
  6809.  
  6810.     // Retry if there are more retries left, otherwise return with timeout
  6811.     // status.
  6812.     if (commandBusy)
  6813.     {
  6814.         if (((SInt8) pFWIMAsynchCommandParams->numRetries--) > 0)
  6815.         {
  6816.             status = PeleFWIMLock (pFWIMAsynchCommandParams, &commandAcceptance);//zzz shouldn't have to pass in commandAcceptance
  6817.         }
  6818.         else
  6819.         {
  6820.             status = timeoutErr;
  6821.         }
  6822.  
  6823.         if (status != noErr)
  6824.             commandBusy = false;
  6825.     }
  6826.  
  6827.     // Complete command if it's no longer busy.
  6828.     if (!commandBusy)
  6829.     {
  6830.         pPeleFWIMData->pPendingFWIMCommand = nil;
  6831.         status =
  6832.             FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
  6833.     }
  6834.  
  6835.     return status;
  6836. }
  6837.  
  6838.  
  6839. ////////////////////////////////////////////////////////////////////////////////
  6840. //
  6841. // PeleFWIMDMAARDeferredTask
  6842. //
  6843. //   Dispatches self-ID and asynch packets after DMA is finished
  6844. //
  6845.  
  6846. static void    PeleFWIMDMAARDeferredTask(
  6847.     void                        *p1,
  6848.     void                        *p2)
  6849. {
  6850.     PeleFWIMDataPtr                pPeleFWIMData = (PeleFWIMDataPtr) p1;
  6851.     PeleDMAPtr                    pDMA;//, pSkimDMA;
  6852.     PeleAsynchRxDMADataPtr        pRxDMAData;//, pLastSelfIDsRxDMAData, pSkimRxDMAData;
  6853.     UInt32                        dmaResult;//, skimStatus;
  6854.     UInt32                        packetSize;//, skimSize;
  6855.     Ptr                            packetBuffer;
  6856.     UInt32                        packetStatus, ackSent;
  6857. //    UInt32                        quad0, quad1;
  6858. //    Boolean                        skimDone;
  6859. //    UInt32                        skipCount;
  6860. //    static UInt32                skipTotal = 0;
  6861.     OSStatus                    status = noErr;
  6862.  
  6863.     // Asynch receive DT no longer scheduled.
  6864.     pPeleFWIMData->asynchReceiveDTScheduled = false;
  6865.  
  6866.     // This is part of a temporary hack.
  6867.     // Within 50ms after a bus reset, don't accept any packets.
  6868.     // We'll get called again after these flags are cleared.
  6869.     
  6870.     if ((pPeleFWIMData->delayedResetTimerSet) || (pPeleFWIMData->busResetDTScheduled))
  6871.         return;
  6872.  
  6873.     // Get next descriptor to process and its data.
  6874.     pRxDMAData = pPeleFWIMData->pNextAsynchRxDMAData;
  6875.     if (pRxDMAData != nil)
  6876.     {
  6877.         pDMA = pRxDMAData->pDMA;
  6878.         dmaResult = EndianSwap32Bit (pDMA->result);
  6879.     }
  6880.     else
  6881.     {
  6882.         dmaResult = 0;
  6883.     }
  6884.  
  6885.     // Process all descriptors with data.
  6886.     while (dmaResult & kPeleXferStatusActive)
  6887.     {
  6888.         // Set next PCL to process.
  6889.         pPeleFWIMData->pNextAsynchRxDMAData = pRxDMAData->pNextRxDMAData;
  6890.  
  6891.         // If this packet is self-IDs, and we are running behind, then
  6892.         // there could be *another* packet with self-IDs waiting too.
  6893.         // In that case, we can avoid a bunch of PHY register reads
  6894.         // and other work by just skipping to the last available self-IDs.
  6895.         // The skipped packets can't contain any responses we want, and
  6896.         // we will be unable to reply to any requests during that period,
  6897.         // so we can safely dispose of all of the packets.
  6898.         
  6899.         // In theory it is possible for someone to have sent us a write
  6900.         // request to which we sent ack_complete.  However, because this
  6901.         // write request was sent after a bus reset, and before we had ever
  6902.         // identified ourselves, the sender has no way to know who we are.
  6903.         // So we can safely ignore such a request even if we said ack_complete.
  6904.         
  6905.         // zzz However, if someone sent a *broadcast* write, they might reasonably
  6906.         // except us to (try to) receive it.  If we find a broadcast write while
  6907.         // scanning ahead, we really ought to stop scanning at that point.
  6908.         
  6909.         packetBuffer = pRxDMAData->packetBuffer;
  6910.         packetSize = kAsyncRxPacketBufferSize - (dmaResult & kPeleResCountMask);
  6911.         packetStatus = *((UInt32 *) (packetBuffer + packetSize - 4));
  6912.         ackSent = packetStatus & kPelePacketAckSent;
  6913.         
  6914.         // If we really sent an ack, then process the packet only if we didn't
  6915.         // complain (ackDataErr, etc.)  In cases where we didn't send an ack,
  6916.         // this value will be ackComplete if Pele found nothing wrong.
  6917.         // If anything went wrong, just recycle the buffer and descriptor.
  6918.         
  6919.         if ((ackSent == kFWAckComplete) || (ackSent == kFWAckPending))
  6920.         {
  6921. #if 0
  6922. zzz
  6923.             // Get first two quads.
  6924.             quad0 = ((UInt32 *) packetBuffer)[0];
  6925.             quad1 = ((UInt32 *) packetBuffer)[1];
  6926.         
  6927.             // If length is zero or first quad is inverse of second quad, assume self-IDs
  6928.             if ((packetSize == 0) || (quad0 == ~quad1))
  6929.             {
  6930.                 // Self-IDs
  6931.                 pLastSelfIDsPCL = pSkimPCL = pPCL;
  6932.                 pSkimPCLData = (PeleAsynchRxDMADataPtr) pSkimPCL->refCon;
  6933.                 skimStatus = EndianSwap32Bit (pPCL->status);
  6934.                 skimDone = false;
  6935.                 
  6936.                 while (skimDone == false)
  6937.                 {
  6938.                     // Move to next PCL
  6939.                     pSkimPCL = pSkimPCLData->pNextPCL;
  6940.                     if (pSkimPCL == nil)
  6941.                     {
  6942.                         // Hit the end of the list
  6943.                         skimDone = true;
  6944.                     }
  6945.                     else
  6946.                     {
  6947.                         pSkimPCLData = (PeleAsynchRxDMADataPtr) pSkimPCL->refCon;
  6948.                         skimStatus = EndianSwap32Bit (pSkimPCL->status);
  6949.                     }
  6950.                     
  6951.                     if ((skimDone == false) && (skimStatus & kPelePktCmp))
  6952.                     {
  6953.                         // pSkimPCL points to a PCL that has been executed
  6954.                         // If this one had an error, just keep looking.
  6955.                         if (!(skimStatus & (kPeleMstErr | kPelePktErr)))
  6956.                         {
  6957.                             // Get packet buffer and length.
  6958.                             skimSize = (skimStatus & kPeleTransferredCount) >>
  6959.                                          kPeleTransferredCountPhase;
  6960.                 
  6961.                             // Get first two quads.
  6962.                             quad0 = ((UInt32 *) pSkimPCLData->packetBuffer)[0];
  6963.                             quad1 = ((UInt32 *) pSkimPCLData->packetBuffer)[1];
  6964.                         
  6965.                             // If length is zero or first quad is inverse of second quad, assume self-IDs
  6966.                             if ((skimSize == 0) || (quad0 == ~quad1))
  6967.                             {
  6968.                                 // This is the latest point we can skip ahead to (so far)
  6969.                                 pLastSelfIDsPCL = pSkimPCL;
  6970.                             }
  6971.                         }
  6972.                     }
  6973.                     else    // ran out of places to look
  6974.                     {
  6975.                         skimDone = true;
  6976.                     }
  6977.                 }
  6978.                 
  6979.                 if (pLastSelfIDsPCL != pPCL)
  6980.                 {
  6981.                     // recycle skipped PCLs and
  6982.                     // set up for alternate
  6983.                     
  6984.                     skipCount = 0;
  6985.                     while (pPCL != pLastSelfIDsPCL)
  6986.                     {
  6987.                         // Add PCL back to active list.
  6988.                         pSkimPCLData = (PeleAsynchRxDMADataPtr) pPCL->refCon;
  6989.                         pSkimPCL = pSkimPCLData->pNextPCL;
  6990.                         PeleFWIMAddAsynchRxDMA (pPCL);
  6991.                         pPCL = pSkimPCL;
  6992.                         skipCount++;
  6993.                         skipTotal++;
  6994.                     }
  6995.                     
  6996.                     pPeleAsynchRxDMAData = (PeleAsynchRxDMADataPtr) pPCL->refCon;
  6997.                     pPeleFWIMData->pNextAsynchRxDMAData = pPeleAsynchRxDMAData->pNextPCL;
  6998.                     pclStatus = EndianSwap32Bit (pPCL->status);
  6999.                     packetBuffer = pPeleAsynchRxDMAData->packetBuffer;
  7000.                     packetSize = (pclStatus & kPeleTransferredCount) >>
  7001.                                  kPeleTransferredCountPhase;
  7002.                     
  7003.                     //sprintf (fireBug, "PeleFWIM: Skipped %ld useless packets [%ld total]",
  7004.                     //         (long) skipCount, (long) skipTotal);
  7005.                     //PeleFWIMFireBugMsg (pPeleFWIMData, fireBug);
  7006.                 }
  7007.             }
  7008. #endif
  7009.             // Process packet.
  7010.             PeleFWIMProcessPacket (pPeleFWIMData, pRxDMAData, packetBuffer, packetSize);
  7011.         }
  7012.         else
  7013.         {
  7014.             // Add back to active list.
  7015.             PeleFWIMAddAsynchRxDMA (pRxDMAData);
  7016.         }
  7017.  
  7018.         // Process next descriptor, if it's ready.
  7019.         pRxDMAData = pPeleFWIMData->pNextAsynchRxDMAData;
  7020.         if (pRxDMAData != nil)
  7021.         {
  7022.             pDMA = pRxDMAData->pDMA;
  7023.             dmaResult = EndianSwap32Bit (pDMA->result);
  7024.         }
  7025.         else
  7026.         {
  7027.             dmaResult = 0;
  7028.         }
  7029.     }
  7030. }
  7031.  
  7032.  
  7033. ////////////////////////////////////////////////////////////////////////////////
  7034. //
  7035. // PeleFWIMDMAIsochReceiveDeferredTask
  7036. //
  7037. //   Handles DMA interrupts for isochronous receive.
  7038. //
  7039.  
  7040. static void    PeleFWIMDMAIsochReceiveDeferredTask(
  7041.     void                        *p1,
  7042.     void                        *p2)
  7043. {
  7044.     PeleFWIMDataPtr                pPeleFWIMData = (PeleFWIMDataPtr) p1;
  7045.     PeleIsochPortDataPtr        pPeleIsochPortData;
  7046.     static DCLCommandPtr        pDCLInterruptList[100];//zzz fixed for now, dynamically allocate later.
  7047.     DCLCommandPtr                pDCLInterrupt,
  7048.                                 pPrevDCLInterrupt;
  7049.     DCLCommandPtr                pDCLCommand;
  7050.     PeleDCLCompilerDCLDataPtr    pPeleDCLCompilerDCLData;
  7051.     DCLCallProcPtr                pDCLCallProc;
  7052.     DCLUpdateDCLListPtr            pDCLUpdateDCLList;
  7053.     UInt32                        numInterrupts;
  7054.     OSStatus                    status = noErr;
  7055.  
  7056.     FWDebugStr ((ConstStr255Param) "\pPeleFWIMIsochReceiveDeferredTask");
  7057.  
  7058.     // Isoch receive DT no longer scheduled.
  7059.     pPeleFWIMData->isochReceiveDTScheduled = false;
  7060.  
  7061.     // Get isoch port data.
  7062.     pPeleIsochPortData = pPeleFWIMData->lynxIsochPortDataList[kIsochReceiveDMA];
  7063.  
  7064.     // Get and clear interrupt queue tail.
  7065.     pDCLInterrupt = pPeleFWIMData->pDCLInterruptTail[kIsochReceiveDMA];
  7066.     while (!CompareAndSwap
  7067.                 ((UInt32) pDCLInterrupt,
  7068.                  nil,
  7069.                  (UInt32 *) &(pPeleFWIMData->pDCLInterruptTail[kIsochReceiveDMA])))
  7070.     {
  7071.         pDCLInterrupt = pPeleFWIMData->pDCLInterruptTail[kIsochReceiveDMA];
  7072.     }
  7073.  
  7074.     
  7075.     // Build interrupt list and clear interrupts.
  7076.     numInterrupts = 0;
  7077.     
  7078. // I thought this was increased to 100 - bug in LynxFWIM sample code too?
  7079.  
  7080.     while ((pDCLInterrupt != nil) && (numInterrupts < 10))
  7081.     {
  7082.         // Value we get back from STORE_QUAD has been endian-swapped:
  7083.         //zzz could we fix that when writing the program?!
  7084.         
  7085.         pDCLInterrupt = (DCLCommandPtr) EndianSwap32Bit ((UInt32) pDCLInterrupt);
  7086.  
  7087.         pDCLInterruptList[numInterrupts] = pDCLInterrupt;
  7088.         pPeleDCLCompilerDCLData = (PeleDCLCompilerDCLDataPtr) pDCLInterrupt->compilerData;
  7089.         pPrevDCLInterrupt = (DCLCommandPtr) pPeleDCLCompilerDCLData->pDMA->cmdDep;
  7090.         pPeleDCLCompilerDCLData->pDMA->cmdDep = nil;
  7091.         numInterrupts++;
  7092.  
  7093.         pDCLInterrupt = pPrevDCLInterrupt;
  7094.     }
  7095.  
  7096.     // Run through interrupt queue.
  7097.     while (numInterrupts--)
  7098.     {
  7099.         // Get DCL command that caused interrupt.
  7100.         pDCLCommand = pDCLInterruptList[numInterrupts];
  7101.  
  7102. //zzz
  7103. //        pPeleDCLCompilerDCLData = (PeleDCLCompilerDCLDataPtr) pDCLCommand->compilerData;
  7104. //        sprintf (debugStr, "Interrupt DCL %08lx (DBDMA %08lx)",
  7105. //                 (long) pDCLCommand,
  7106. //                 (long) pPeleDCLCompilerDCLData->pDMA);
  7107. //        FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  7108. //zzz
  7109.  
  7110.         // Dispatch off of opcode.
  7111.         switch (pDCLCommand->opcode & ~kFWDCLOpFlagMask)
  7112.         {
  7113.             case kDCLCallProcOp :
  7114.                 // Call the proc.
  7115.                 pDCLCallProc = (DCLCallProcPtr) pDCLCommand;
  7116.                 FWCallDCLCallProc (pPeleIsochPortData->dclProgramID, pDCLCallProc);
  7117.                 break;
  7118.  
  7119.             case kDCLUpdateDCLListOp :
  7120.                 // Update the DCL list.
  7121.                 pDCLUpdateDCLList = (DCLUpdateDCLListPtr) pDCLCommand;
  7122.                 PeleFWIMDCLCompilerUpdateNotification (pPeleIsochPortData->dclProgramID,
  7123.                                                        pDCLUpdateDCLList->dclCommandList,
  7124.                                                        pDCLUpdateDCLList->numDCLCommands);
  7125.                 break;
  7126.  
  7127.             default :
  7128.                 break;
  7129.         }
  7130.     }
  7131. }
  7132.  
  7133.  
  7134. ////////////////////////////////////////////////////////////////////////////////
  7135. //
  7136. // PeleFWIMDMAIsochTransmitDeferredTask
  7137. //
  7138. //   Handles DMA interrupts for isochronous transmit.
  7139. //
  7140.  
  7141. static void    PeleFWIMDMAIsochTransmitDeferredTask(
  7142.     void                        *p1,
  7143.     void                        *p2)
  7144. {
  7145.     PeleFWIMDataPtr                pPeleFWIMData = (PeleFWIMDataPtr) p1;
  7146.     PeleIsochPortDataPtr        pPeleIsochPortData;
  7147.     static DCLCommandPtr        pDCLInterruptList[100];//zzz fixed for now, dynamically allocate later.
  7148.     DCLCommandPtr                pDCLInterrupt,
  7149.                                 pPrevDCLInterrupt;
  7150.     PeleDCLCompilerDCLDataPtr    pPeleDCLCompilerDCLData;
  7151.     DCLCommandPtr                pDCLCommand;
  7152.     DCLCallProcPtr                pDCLCallProc;
  7153.     DCLUpdateDCLListPtr            pDCLUpdateDCLList;
  7154.     UInt32                        numInterrupts;
  7155.     OSStatus                    status = noErr;
  7156.  
  7157.     // Isoch transmit DT no longer scheduled.
  7158.     pPeleFWIMData->isochTransmitDTScheduled = false;
  7159.  
  7160.     // Get isoch port data.
  7161.     pPeleIsochPortData = pPeleFWIMData->lynxIsochPortDataList[kIsochTransmitDMA];
  7162.  
  7163.     // Get and clear interrupt queue tail.
  7164.     pDCLInterrupt = pPeleFWIMData->pDCLInterruptTail[kIsochTransmitDMA];
  7165.     while (!CompareAndSwap
  7166.                 ((UInt32) pDCLInterrupt,
  7167.                  nil,
  7168.                  (UInt32 *) &(pPeleFWIMData->pDCLInterruptTail[kIsochTransmitDMA])))
  7169.     {
  7170.         pDCLInterrupt = pPeleFWIMData->pDCLInterruptTail[kIsochTransmitDMA];
  7171.     }
  7172.  
  7173.     // Build interrupt list and clear interrupts.
  7174.     numInterrupts = 0;
  7175.     while ((pDCLInterrupt != nil) && (numInterrupts < 10))
  7176.     {
  7177.         // Value we get back from STORE_QUAD has been endian-swapped:
  7178.         //zzz could we fix that when writing the program?!
  7179.         
  7180.         pDCLInterrupt = (DCLCommandPtr) EndianSwap32Bit ((UInt32) pDCLInterrupt);
  7181.         
  7182.         pDCLInterruptList[numInterrupts] = pDCLInterrupt;
  7183.         pPeleDCLCompilerDCLData = (PeleDCLCompilerDCLDataPtr) pDCLInterrupt->compilerData;
  7184.         pPrevDCLInterrupt = (DCLCommandPtr) pPeleDCLCompilerDCLData->pDMA->cmdDep;
  7185.         pPeleDCLCompilerDCLData->pDMA->cmdDep = nil;
  7186.         numInterrupts++;
  7187.  
  7188.         pDCLInterrupt = pPrevDCLInterrupt;
  7189.     }
  7190.  
  7191.     // Run through interrupt queue.
  7192.     while (numInterrupts--)
  7193.     {
  7194.         // Get DCL command that caused interrupt.
  7195.         pDCLCommand = pDCLInterruptList[numInterrupts];
  7196.  
  7197.         // Dispatch off of opcode.
  7198.         switch (pDCLCommand->opcode & ~kFWDCLOpFlagMask)
  7199.         {
  7200.             case kDCLCallProcOp :
  7201.                 // Call the proc.
  7202.                 pDCLCallProc = (DCLCallProcPtr) pDCLCommand;
  7203.                 FWCallDCLCallProc (pPeleIsochPortData->dclProgramID, pDCLCallProc);
  7204.                 break;
  7205.  
  7206.             case kDCLUpdateDCLListOp :
  7207.                 // Update the DCL list.
  7208.                 pDCLUpdateDCLList = (DCLUpdateDCLListPtr) pDCLCommand;
  7209.                 PeleFWIMDCLCompilerUpdateNotification (pPeleIsochPortData->dclProgramID,
  7210.                                                        pDCLUpdateDCLList->dclCommandList,
  7211.                                                        pDCLUpdateDCLList->numDCLCommands);
  7212.                 break;
  7213.  
  7214.             default :
  7215.                 break;
  7216.         }
  7217.     }
  7218. }
  7219.  
  7220.  
  7221. ////////////////////////////////////////////////////////////////////////////////
  7222. //
  7223. // PeleFWIMResetDeferredTask
  7224. //
  7225. //   This proc deals with bus resets at FireWire deferred task time.
  7226. //
  7227.  
  7228. static void    PeleFWIMResetDeferredTask(
  7229.     void                        *p1,
  7230.     void                        *p2)
  7231. {
  7232.     PeleFWIMDataPtr                pPeleFWIMData = (PeleFWIMDataPtr) p1;
  7233.     AbsoluteTime                timeoutAbsolute;
  7234.     OSStatus                    status = noErr;
  7235.  
  7236. //    FWDebugStr ((ConstStr255Param) "\pPeleFWIMResetDeferredTask");
  7237.     
  7238.     // Bus reset DT no longer scheduled.
  7239.     pPeleFWIMData->busResetDTScheduled = false;
  7240.  
  7241.     // This is a temporary hack.  We want to reduce the risk of PHY jams.
  7242.     // So after a bus reset, before we process the self-IDs, wait 50ms to
  7243.     // allow another bus reset (if any) to arrive.  When this timer goes
  7244.     // off, if busResetDTScheduled has become true again, then there was
  7245.     // another bus reset.  By the time we get to the self-IDs for the first
  7246.     // reset, we'll be able to skip forward over them and avoid some PHY
  7247.     // register accesses.
  7248.     
  7249.     // If there are more resets beyond 50ms, we won't keep waiting - otherwise
  7250.     // we might hang if there were endless resets.  But hopefully we will have
  7251.     // managed to skip some of them.
  7252.  
  7253.     if (pPeleFWIMData->delayedResetTimerSet == false)
  7254.     {
  7255.         timeoutAbsolute = AddAbsoluteToAbsolute (UpTime (), DurationToAbsolute (50 * durationMillisecond));
  7256.         status = SetInterruptTimer
  7257.                     (&timeoutAbsolute,
  7258.                      PeleFWIMDelayedReset,
  7259.                      pPeleFWIMData,
  7260.                      &(pPeleFWIMData->delayedResetTimerID));
  7261.         if (status == noErr)
  7262.             pPeleFWIMData->delayedResetTimerSet = true;
  7263.             else PeleFWIMDelayedReset (p1, nil);            // Might as well proceed (should never happen)
  7264.     }
  7265. }
  7266.  
  7267.  
  7268. static OSStatus    PeleFWIMDelayedReset(
  7269.     void                        *p1,
  7270.     void                        *p2)
  7271. {
  7272.     PeleFWIMDataPtr                pPeleFWIMData = (PeleFWIMDataPtr) p1;
  7273.  
  7274.     pPeleFWIMData->delayedResetTimerSet = false;
  7275.  
  7276.     // If there's a pending FWIM command, set its status to busReconfiguredErr.
  7277.     //zzz should we do this here, or in services?
  7278.     //zzz this probably should not be done on all types of commands.
  7279.     if (pPeleFWIMData->pPendingFWIMCommand)
  7280.     {
  7281.         if (pPeleFWIMData->pendingFWIMCommandStatus == kPelePendingFWIMCommandBusy)
  7282.             pPeleFWIMData->pendingFWIMCommandStatus = busReconfiguredErr;
  7283.     }
  7284.     
  7285.     // During the period that delayedResetTimerSet was true,
  7286.     // no asynch packets were processed.
  7287.     // Now (another hack) process any that are waiting:
  7288.     
  7289.     PeleFWIMHandleDMAARInterrupt (pPeleFWIMData);
  7290.     
  7291.     return noErr;
  7292. }
  7293.  
  7294.  
  7295. ////////////////////////////////////////////////////////////////////////////////
  7296. //
  7297. // PeleFWIMMiscInterruptDeferredTask
  7298. //
  7299. //   This proc deals with miscellaneous interrupts at FireWire deferred task time.
  7300. //
  7301.  
  7302. static void    PeleFWIMMiscInterruptDeferredTask(
  7303.     void                        *p1,
  7304.     void                        *p2)
  7305. {
  7306.     PeleFWIMDataPtr                pPeleFWIMData = (PeleFWIMDataPtr) p1;
  7307.     UInt32                        i;
  7308.  
  7309.     // DT no longer scheduled.
  7310.     pPeleFWIMData->miscInterruptDTScheduled = false;
  7311.  
  7312.     i = pPeleFWIMData->miscInterrupt;
  7313.     pPeleFWIMData->miscInterrupt = 0;
  7314.  
  7315. #ifdef PeleFireBug
  7316.     sprintf (fireBug, "PeleFWIM:  Interrupts: %s%s%s%s%s%s%s%s%s%s",
  7317.              (i & kPelePHY_TIME_OUT)    ? "PHY_TO "        : "",
  7318.              (i & kPeleIT_STUCK)        ? "IT_STUCK "    : "",
  7319.              (i & kPeleAT_STUCK)        ? "AT_STUCK "    : "",
  7320.              (i & kPeleHDR_ERR)            ? "CRC_ERR "    : "",
  7321.              (i & kPeleTC_ERR)            ? "TC_ERR "        : "",
  7322.              (i & kPeleCYC_LOST)        ? "CYC_LOST "    : "",
  7323.              (i & kPeleCYC_ARB_FAILED)    ? "CYC_ARB "    : "",
  7324.              (i & kPeleITF_UNDER_FLOW)    ? "ITF_UF "        : "",
  7325.              (i & kPeleATF_UNDER_FLOW)    ? "ATF_UF "        : "",
  7326.              (i & kPeleIARB_FAILED)        ? "IARB "        : "");
  7327.     //if (i) PeleFWIMFireBugMsg (pPeleFWIMData, fireBug);
  7328. #endif
  7329.  
  7330. }
  7331.  
  7332.  
  7333. ////////////////////////////////////////////////////////////////////////////////
  7334. //
  7335. // PeleFWIMAckSecondaryInterruptHandler
  7336. //
  7337. //   This proc checks the ack received for the sent transaction.  If the ack
  7338. // specifies a completed transaction, this proc will complete the transaction.
  7339. // If the ack specifies an error, this proc will retry the transaction.
  7340. //zzz need to handle response pending ack.
  7341. //zzz need locking mechanism between this routine and the timeout routine
  7342. //
  7343. // We aren't called by interrupt, we're called directly by PeleFWIMWrite()
  7344.  
  7345. static OSStatus    PeleFWIMAckSecondaryInterruptHandler(
  7346.     void                        *p1,
  7347.     void                        *p2)
  7348. {
  7349.     FWIMCommandParamsPtr        pFWIMCommandParams;
  7350.     FWIMAsynchCommandParamsPtr    pFWIMAsynchCommandParams;
  7351.     PeleFWIMDataPtr                pPeleFWIMData = (PeleFWIMDataPtr) p1; 
  7352.     PeleDMAPtr                    pPCL = (PeleDMAPtr) p2;
  7353.     AbsoluteTime                timeoutAbsolute;
  7354.     UInt32                        ackCode, ackType, tryAgain;
  7355.     Boolean                        commandBusy;
  7356.     OSStatus                    pendingFWIMCommandStatus,
  7357.                                 status = noErr;
  7358.  
  7359. //    FWDebugStr ((ConstStr255Param) "\pPeleFWIMAckSecondaryInterruptHandler");
  7360.  
  7361.     // Get our internal data.
  7362.     pFWIMAsynchCommandParams =
  7363.         (FWIMAsynchCommandParamsPtr) pPeleFWIMData->pPendingFWIMCommand;
  7364.     pendingFWIMCommandStatus = pPeleFWIMData->pendingFWIMCommandStatus;
  7365.     pFWIMCommandParams = &(pFWIMAsynchCommandParams->fwimCommandParams);
  7366.  
  7367.     // Make sure pending command is a write.
  7368.     if (pFWIMCommandParams->commandType == kFWIMWrite)
  7369.     {
  7370.         if (status == noErr)
  7371.         {
  7372.             // Check if command is still busy.
  7373.             if (pendingFWIMCommandStatus == kPelePendingFWIMCommandBusy)
  7374.             {
  7375.                 commandBusy = true;
  7376.             }
  7377.             else
  7378.             {
  7379.                 commandBusy = false;
  7380.                 status = pendingFWIMCommandStatus;
  7381.             }
  7382.     
  7383.             // Check if ack code indicates a completed transfer.  Retry if it doesn't.
  7384.             if (commandBusy)
  7385.             {
  7386. //zzz fake ack complete
  7387. ackCode = 1;
  7388. ackType = 0;
  7389.  
  7390. // This is where to look for the real ack:
  7391. // pPeleFWIMData->asynchTxDoneDMASegment->pDMA->result
  7392.  
  7393. //                ackCode = (EndianSwap32Bit (pPCL->status) & kPeleAcks) >> kPeleAcksPhase;
  7394. //                ackType = ((EndianSwap32Bit (pPCL->status) & kPeleAck_Type) != 0);
  7395.                 tryAgain = 0;
  7396.                 
  7397.                 if (ackType == 0)        // Normal 1394 ack
  7398.                 {
  7399.                     if ((ackCode == kFWAckComplete) || (ackCode == kFWAckPending))
  7400.                     {
  7401.                         // This happens the majority of the time.
  7402.                         //zzz should wait for write response when ack pending
  7403.                         commandBusy = false;
  7404.                     }
  7405.                     else if (ackCode != kFWAckTypeError)
  7406.                     {
  7407.                         // This should only be AckDataError, meaning the packet we sent
  7408.                         // failed CRC at the receiver.  However, non-revA parts seem to
  7409.                         // yield ack 0 in this case.  So except for TypeError, just try
  7410.                         // again.  TypeError will probably fail again if we try again,
  7411.                         // so give up in that case.
  7412.                         tryAgain = 1;
  7413.                     }
  7414.                     else        // TypeError
  7415.                     {
  7416.                         commandBusy = false;
  7417.                         status = retryExceededErr;    //zzz do we have a better error code?
  7418.                     }
  7419.                 }
  7420.                 else                    // Some Pele error code, not a real ack
  7421.                 {
  7422.                     if ((ackCode == 0) || (ackCode == 1))
  7423.                     {
  7424.                         // 0 indicates retry overrun (too many retries)
  7425.                         // 1 indicates Link Timeout - meaning nobody home.  Assume no Link at that Phy.
  7426.                         status = retryExceededErr;
  7427.                         commandBusy = false;
  7428.                     }
  7429.                     else if (ackCode == 2)
  7430.                     {
  7431.                         // 2 indicates FIFO underrun.  This happens sometimes.
  7432.                         // Just try again.
  7433.                         // zzz should only retry a limited number of times.
  7434.                         tryAgain = 1;
  7435.                     }
  7436.                 }
  7437.             }
  7438.                 
  7439.             if (tryAgain)
  7440.             {
  7441.                 timeoutAbsolute =
  7442.                     AddAbsoluteToAbsolute (UpTime (), DurationToAbsolute (10 * durationMillisecond));
  7443.                 status = SetInterruptTimer
  7444.                             (&timeoutAbsolute,
  7445.                              PeleFWIMWriteTimer,
  7446.                              pFWIMAsynchCommandParams,
  7447.                              &(pPeleFWIMData->requestTimeoutTimerID));
  7448.                 if (status == noErr)
  7449.                     pPeleFWIMData->requestTimeoutTimerSet = true;
  7450.  
  7451.                 if (status != noErr)
  7452.                     commandBusy = false;
  7453.             }
  7454.             
  7455.             // Complete command if it's no longer busy.
  7456.             if (!commandBusy)
  7457.             {
  7458.                 pPeleFWIMData->pPendingFWIMCommand = nil;
  7459.                 status =
  7460.                     FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID,
  7461.                                            status);
  7462.             }
  7463.         }
  7464.     }
  7465.  
  7466.     return status;
  7467. }
  7468.  
  7469.  
  7470. ////////////////////////////////////////////////////////////////////////////////
  7471. //
  7472. // PeleFWIMProcessPacket
  7473. //
  7474. //   Dispatch packet processing based on tCode (asynch or isoch).
  7475. //zzz check destID???
  7476. //
  7477.  
  7478. static void PeleFWIMProcessPacket(
  7479.     PeleFWIMDataPtr                pPeleFWIMData,
  7480.     PeleAsynchRxDMADataPtr        pRxDMAData,
  7481.     Ptr                            packetBuffer,
  7482.     UInt32                        packetSize)
  7483. {
  7484.     UInt32                        tCode;
  7485.     UInt32                        quad0;
  7486.  
  7487.     // Get first two quads.
  7488.     quad0 = ((UInt32 *) packetBuffer)[0];
  7489.  
  7490.     tCode = (quad0 & kPelePacketTCode) >> kPelePacketTCodePhase;
  7491.  
  7492. #if 0
  7493. zzz check ack sent if not self-id - its in the packet trailer
  7494.     if (tCode != kPeleTCodeSelfID)
  7495.     {
  7496.         pclStatus = EndianSwap32Bit (pPCL->status);
  7497.         ackCode = (pclStatus & kPeleAcks) >> kPeleAcksPhase;
  7498.         if ((ackCode != 1) && (ackCode != 2))
  7499.         {
  7500.             tCode = 0x0f;    // reserved
  7501.             
  7502.             //sprintf (fireBug, "PeleFWIM: Whoops, ack %ld in received packet [%08lx]",
  7503.             //         (long) ackCode, (long) pclStatus);
  7504.             //PeleFWIMFireBugMsg (pPeleFWIMData, fireBug);
  7505.         }
  7506.     }
  7507. #endif
  7508.  
  7509.     // Dispatch processing based on tCode.
  7510.     switch (tCode)
  7511.     {
  7512.         case kFWTCodeWriteQuadlet :
  7513.             PeleFWIMProcessWriteQuadletPacket
  7514.                 (pPeleFWIMData, pRxDMAData, packetBuffer, packetSize);
  7515.             break;
  7516.  
  7517.         case kFWTCodeWriteBlock :
  7518.             PeleFWIMProcessWriteBlockPacket
  7519.                 (pPeleFWIMData, pRxDMAData, packetBuffer, packetSize);
  7520.             break;
  7521.  
  7522.         case kFWTCodeWriteResponse :
  7523.             PeleFWIMProcessWriteResponsePacket
  7524.                 (pPeleFWIMData, pRxDMAData, packetBuffer, packetSize);
  7525.             break;
  7526.  
  7527.         case kFWTCodeReadQuadlet :
  7528.             PeleFWIMProcessReadQuadletPacket
  7529.                 (pPeleFWIMData, pRxDMAData, packetBuffer, packetSize);
  7530.             break;
  7531.  
  7532.         case kFWTCodeReadBlock :
  7533.             PeleFWIMProcessReadBlockPacket
  7534.                 (pPeleFWIMData, pRxDMAData, packetBuffer, packetSize);
  7535.             break;
  7536.  
  7537.         case kFWTCodeReadQuadletResponse :
  7538.             PeleFWIMProcessReadQuadletResponsePacket
  7539.                 (pPeleFWIMData, pRxDMAData, packetBuffer, packetSize);
  7540.             break;
  7541.  
  7542.         case kFWTCodeReadBlockResponse :
  7543.             PeleFWIMProcessReadBlockResponsePacket
  7544.                 (pPeleFWIMData, pRxDMAData, packetBuffer, packetSize);
  7545.             break;
  7546.  
  7547.         case kFWTCodeLock :
  7548.             PeleFWIMProcessLockPacket
  7549.                 (pPeleFWIMData, pRxDMAData, packetBuffer, packetSize);
  7550.             break;
  7551.  
  7552.         case kFWTCodeLockResponse :
  7553.             PeleFWIMProcessLockResponsePacket
  7554.                 (pPeleFWIMData, pRxDMAData, packetBuffer, packetSize);
  7555.             break;
  7556.  
  7557.         case kPeleTCodeSelfID :
  7558.             PeleFWIMProcessSelfIDPacket
  7559.                 (pPeleFWIMData, pRxDMAData, packetBuffer, packetSize);
  7560.             break;
  7561.  
  7562.         default :
  7563.             PeleFWIMAddAsynchRxDMA (pRxDMAData);
  7564.             break;
  7565.     }
  7566. }
  7567.  
  7568.  
  7569. ////////////////////////////////////////////////////////////////////////////////
  7570. //
  7571. // PeleFWIMProcessSelfIDPacket
  7572. //
  7573. //   This proc tries to process a selfID packet.
  7574. //zzz Should validate selfIDs by making sure the phyID is correct , there's
  7575. //zzz enough of them, etc.  Need to generate CRC. Should cancel timeout timer.
  7576. //
  7577.  
  7578. static void    PeleFWIMProcessSelfIDPacket(
  7579.     PeleFWIMDataPtr                pPeleFWIMData,
  7580.     PeleAsynchRxDMADataPtr        pRxDMAData,
  7581.     Ptr                            packetBuffer,
  7582.     UInt32                        packetSize)
  7583. {
  7584.     PeleRegistersPtr            pPeleRegs;
  7585.     FWIMProcessSelfIDsParams    fwimProcessSelfIDsParams;
  7586.     UInt32                        localSelfIDQuads[2];
  7587.     UInt32                        *pSelfIDPackets = (UInt32 *) packetBuffer;
  7588.     UInt32                        localSelfID;
  7589.     UInt32                        physicalID;
  7590.     UInt32                        gapCount;                        
  7591.     UInt32                        speed;
  7592.     UInt32                        contender;
  7593.     UInt32                        portStatus;
  7594.  
  7595. //    FWDebugStr ((ConstStr255Param) "\pPeleFWIMProcessSelfIDPacket");
  7596.  
  7597.     if ((packetSize == 8) && ((pSelfIDPackets[1] & 0xFFFFFFF0) != 0))
  7598.     {
  7599.         // packetSize == 8, must be empty-bus selfIDs or a PHY packet.
  7600.         // If anything other than the ack is in the second quadlet, it's PHY:
  7601.         
  7602.         PeleFWIMAddAsynchRxDMA (pRxDMAData);
  7603.         return;
  7604.     }
  7605.  
  7606.     pPeleRegs = pPeleFWIMData->pPeleRegisters;
  7607.  
  7608.     ////////////////////////////////////////////////////////////////////////////
  7609.     //
  7610.     // Build our local selfID.
  7611.     //
  7612.  
  7613. //zzz check for ack_complete in packet trailer to indicate OK reception.
  7614.  
  7615.     // Get physical ID and root bit.
  7616.     physicalID = PeleFWIMReadPhyRegister (pPeleFWIMData, pPeleRegs, kPelePhyPhysicalIDAddress);
  7617.     if (physicalID & kPelePhyR)
  7618.         pPeleFWIMData->root = true;
  7619.     else
  7620.         pPeleFWIMData->root = false;
  7621.     physicalID = (physicalID & kPelePhyPhysicalID) >> kPelePhyPhysicalIDPhase;
  7622.     localSelfID = physicalID << kFWSelfIDPhyIDPhase;
  7623.  
  7624.     // This will have already been done by the PhyReg primary interrupt handler.
  7625.     // But do it again here just to be safe (there is a possible race condition)
  7626.     
  7627.     // Disable cycle mastering if we're not root.
  7628.     if (!pPeleFWIMData->root)
  7629.     {
  7630.         pPeleRegs->control &= ~EndianSwapImm32Bit (kPeleControlCycleMaster);
  7631.         SynchronizeIO ();
  7632.     }
  7633.  
  7634.     // Get gap count.
  7635.     gapCount = PeleFWIMReadPhyRegister (pPeleFWIMData, pPeleRegs, kPelePhyGCAddress);
  7636.     gapCount = (gapCount & kPelePhyGC) >> kPelePhyGCPhase;
  7637.     localSelfID |= gapCount << kFWSelfID0GapCntPhase;
  7638.  
  7639.     // Get speed.
  7640.     speed = PeleFWIMReadPhyRegister (pPeleFWIMData, pPeleRegs, kPelePhySPDAddress);
  7641.     speed = (speed & kPelePhySPD) >> kPelePhySPDPhase;
  7642.     localSelfID |= speed << kFWSelfID0SPPhase;
  7643.  
  7644.     // Get contender bit.
  7645. //zzz assume hardwired to 1
  7646.     contender = 1;
  7647.     if (contender & 1)
  7648.         localSelfID |= kFWSelfID0C;
  7649. /*zzz should do it like this. */
  7650. #if 0
  7651.     contender = PeleFWIMReadPhyRegister (pPeleFWIMData, pPeleRegs, kPelePhyCAddress);
  7652.     if (contender & kPelePhyC)
  7653.         localSelfID |= kFWSelfID0C;
  7654. #endif
  7655.  
  7656.     // Get port status p0.
  7657.     portStatus = PeleFWIMReadPhyRegister (pPeleFWIMData, pPeleRegs, kPelePhyPortStatus1Address);
  7658.     if (portStatus & kPelePhyCon1)
  7659.     {
  7660.         if (portStatus & kPelePhyCh1)
  7661.             localSelfID |= kFWSelfIDPortStatusChild << kFWSelfID0P0Phase;
  7662.         else
  7663.             localSelfID |= kFWSelfIDPortStatusParent << kFWSelfID0P0Phase;
  7664.     }
  7665.     else
  7666.     {
  7667.         localSelfID |= kFWSelfIDPortStatusNotConnected << kFWSelfID0P0Phase;
  7668.     }
  7669.  
  7670.     // Get port status p1.
  7671.     portStatus = PeleFWIMReadPhyRegister (pPeleFWIMData, pPeleRegs, kPelePhyPortStatus2Address);
  7672.     if (portStatus & kPelePhyCon2)
  7673.     {
  7674.         if (portStatus & kPelePhyCh2)
  7675.             localSelfID |= kFWSelfIDPortStatusChild << kFWSelfID0P1Phase;
  7676.         else
  7677.             localSelfID |= kFWSelfIDPortStatusParent << kFWSelfID0P1Phase;
  7678.     }
  7679.     else
  7680.     {
  7681.         localSelfID |= kFWSelfIDPortStatusNotConnected << kFWSelfID0P1Phase;
  7682.     }
  7683.  
  7684.     // Get port status p2.
  7685.     portStatus = PeleFWIMReadPhyRegister (pPeleFWIMData, pPeleRegs, kPelePhyPortStatus3Address);
  7686.     if (portStatus & kPelePhyCon3)
  7687.     {
  7688.         if (portStatus & kPelePhyCh3)
  7689.             localSelfID |= kFWSelfIDPortStatusChild << kFWSelfID0P2Phase;
  7690.         else
  7691.             localSelfID |= kFWSelfIDPortStatusParent << kFWSelfID0P2Phase;
  7692.     }
  7693.     else
  7694.     {
  7695.         localSelfID |= kFWSelfIDPortStatusNotConnected << kFWSelfID0P2Phase;
  7696.     }
  7697.  
  7698.     // Set selfID packet ID, link active, self powered and
  7699.     // provides 15W.
  7700.     //zzz 15W is just a guess.  Need to determine real number.
  7701.     localSelfID |= ((kFWSelfIDPacketID << kFWPhyPacketIDPhase) |
  7702.                     kFWSelfID0L |
  7703.                     (kFWSelfIDSelfPowered15W << kFWSelfID0PwrPhase));
  7704.  
  7705.     // Process the self IDs.
  7706.     //zzz need to get status.
  7707.     localSelfIDQuads[0] = localSelfID;
  7708.     localSelfIDQuads[1] = ~localSelfID;
  7709.     fwimProcessSelfIDsParams.fwimProcessParams.fwimID = pPeleFWIMData->fwimID;
  7710.     fwimProcessSelfIDsParams.pSelfIDList = ((Ptr) pSelfIDPackets) + 4;
  7711.     fwimProcessSelfIDsParams.selfIDListSize = packetSize - 8;
  7712.     fwimProcessSelfIDsParams.pLocalSelfID = (Ptr) localSelfIDQuads;
  7713.     fwimProcessSelfIDsParams.localSelfIDSize = 8;
  7714.     fwimProcessSelfIDsParams.processSelfIDsFlags = 0;
  7715.     FWProcessSelfIDs (&fwimProcessSelfIDsParams);
  7716.     
  7717.     pPeleFWIMData->generation = fwimProcessSelfIDsParams.generation;
  7718.     pPeleFWIMData->generationValid = true;
  7719.  
  7720.     // We used to load the nodeID register here, but this was a bad place to
  7721.     // do it.  That's now done based on PHY register receive interrupts.
  7722.     
  7723.     // Add PCL back to active list.
  7724.     PeleFWIMAddAsynchRxDMA (pRxDMAData);
  7725. }
  7726.  
  7727.  
  7728. ////////////////////////////////////////////////////////////////////////////////
  7729. //
  7730. // PeleFWIMProcessWriteQuadletPacket
  7731. //
  7732. //   This proc processes a write quadlet packet.
  7733. //
  7734.  
  7735. static void    PeleFWIMProcessWriteQuadletPacket(
  7736.     PeleFWIMDataPtr                pPeleFWIMData,
  7737.     PeleAsynchRxDMADataPtr        pRxDMAData,
  7738.     Ptr                            packetBuffer,
  7739.     UInt32                        packetSize)
  7740. {
  7741.     UInt32                        *pPacket = (UInt32 *) packetBuffer;
  7742.     FWIMProcessAsynchParamsPtr    pFWIMProcessAsynchParams;
  7743.     UInt32                        trailerQuad;
  7744.     UInt32                        transactionStatus;
  7745.  
  7746. //    FWDebugStr ((ConstStr255Param) "\pPeleFWIMProcessWriteQuadletPacket");
  7747.  
  7748.     // Fill in processing params.
  7749.     pFWIMProcessAsynchParams = &(pRxDMAData->fwimProcessAsynchParams);
  7750.     pFWIMProcessAsynchParams->fwimProcessParams.fwimID = pPeleFWIMData->fwimID;
  7751.     pFWIMProcessAsynchParams->fwimProcessParams.processFlags = 0;
  7752.     pFWIMProcessAsynchParams->fwimProcessParams.completionProc =
  7753.         PeleFWIMProcessWriteQuadletRequestCompletionProc;
  7754.     pFWIMProcessAsynchParams->fwimProcessParams.completionProcData = (UInt32) pRxDMAData;
  7755.     pFWIMProcessAsynchParams->timeStamp = UpTime ();//zzz need more accurate time stamp
  7756.     pFWIMProcessAsynchParams->receiveBuffer = (Ptr) &(pPacket[3]);
  7757.     pFWIMProcessAsynchParams->generation = pPeleFWIMData->generation;//zzz needs to be more accurate.
  7758.     BlockCopy (packetBuffer,
  7759.                &(pFWIMProcessAsynchParams->destinationID),
  7760.                3 * sizeof (UInt32));
  7761.     pFWIMProcessAsynchParams->length = 4;
  7762.     pFWIMProcessAsynchParams->extendedTCode = 0;
  7763.  
  7764.     trailerQuad = *((UInt32 *) (packetBuffer + packetSize - 4));
  7765.     transactionStatus = ((trailerQuad & kPelePacketAckSent) >> kPelePacketAckSentPhase) <<
  7766.                         kFWTransactionStatusAckCodePhase;
  7767.     transactionStatus |= ((trailerQuad & kPelePacketSpd) >> kPelePacketSpdPhase) <<
  7768.                          kFWTransactionStatusSpeedPhase;
  7769.     pFWIMProcessAsynchParams->transactionStatus = transactionStatus;
  7770.  
  7771.     // Process the write request.
  7772.     FWProcessWriteRequest (pFWIMProcessAsynchParams);
  7773. }
  7774.  
  7775.  
  7776. ////////////////////////////////////////////////////////////////////////////////
  7777. //
  7778. // PeleFWIMProcessWriteQuadletRequestCompletionProc
  7779. //
  7780. //   This proc will be called upon completion of write request processing.
  7781. //
  7782.  
  7783. static void    PeleFWIMProcessWriteQuadletRequestCompletionProc(
  7784.     FWIMProcessParamsPtr        pFWIMProcessParams)
  7785. {
  7786.     PeleAsynchRxDMADataPtr        pRxDMAData;
  7787.  
  7788.     // Get PCL pointer.
  7789.     pRxDMAData = (PeleAsynchRxDMADataPtr) pFWIMProcessParams->completionProcData;
  7790.  
  7791.     // Add PCL back to active list.
  7792.     PeleFWIMAddAsynchRxDMA (pRxDMAData);
  7793. }
  7794.  
  7795.  
  7796. ////////////////////////////////////////////////////////////////////////////////
  7797. //
  7798. // PeleFWIMProcessWriteBlockPacket
  7799. //
  7800. //   This proc processes a write block packet.
  7801. //
  7802.  
  7803. static void    PeleFWIMProcessWriteBlockPacket(
  7804.     PeleFWIMDataPtr                pPeleFWIMData,
  7805.     PeleAsynchRxDMADataPtr        pRxDMAData,
  7806.     Ptr                            packetBuffer,
  7807.     UInt32                        packetSize)
  7808. {
  7809.     UInt32                        *pPacket = (UInt32 *) packetBuffer;
  7810.     FWIMProcessAsynchParamsPtr    pFWIMProcessAsynchParams;
  7811.     UInt32                        trailerQuad;
  7812.     UInt32                        transactionStatus;
  7813.  
  7814. //    FWDebugStr ((ConstStr255Param) "\pPeleFWIMProcessWriteBlockPacket");
  7815.         
  7816.     // Fill in processing params.
  7817.     pFWIMProcessAsynchParams = &(pRxDMAData->fwimProcessAsynchParams);
  7818.     pFWIMProcessAsynchParams->fwimProcessParams.fwimID = pPeleFWIMData->fwimID;
  7819.     pFWIMProcessAsynchParams->fwimProcessParams.processFlags = 0;
  7820.     pFWIMProcessAsynchParams->fwimProcessParams.completionProc =
  7821.         PeleFWIMProcessWriteBlockRequestCompletionProc;
  7822.     pFWIMProcessAsynchParams->fwimProcessParams.completionProcData = (UInt32) pRxDMAData;
  7823.     pFWIMProcessAsynchParams->timeStamp = UpTime ();//zzz need more accurate time stamp
  7824.     pFWIMProcessAsynchParams->receiveBuffer = (Ptr) &(pPacket[4]);
  7825.     pFWIMProcessAsynchParams->generation = pPeleFWIMData->generation;//zzz needs to be more accurate.
  7826.     BlockCopy (packetBuffer,
  7827.                &(pFWIMProcessAsynchParams->destinationID),
  7828.                4 * sizeof (UInt32));
  7829.  
  7830.     trailerQuad = *((UInt32 *) (packetBuffer + packetSize - 4));
  7831.     transactionStatus = ((trailerQuad & kPelePacketAckSent) >> kPelePacketAckSentPhase) <<
  7832.                         kFWTransactionStatusAckCodePhase;
  7833.     transactionStatus |= ((trailerQuad & kPelePacketSpd) >> kPelePacketSpdPhase) <<
  7834.                          kFWTransactionStatusSpeedPhase;
  7835.     pFWIMProcessAsynchParams->transactionStatus = transactionStatus;
  7836.  
  7837.     // Process the write request.
  7838.     FWProcessWriteRequest (pFWIMProcessAsynchParams);
  7839. }
  7840.  
  7841.  
  7842. ////////////////////////////////////////////////////////////////////////////////
  7843. //
  7844. // PeleFWIMProcessWriteBlockRequestCompletionProc
  7845. //
  7846. //   This proc will be called upon completion of write request processing.
  7847. //
  7848.  
  7849. static void    PeleFWIMProcessWriteBlockRequestCompletionProc(
  7850.     FWIMProcessParamsPtr        pFWIMProcessParams)
  7851. {
  7852.     PeleAsynchRxDMADataPtr        pRxDMAData;
  7853.  
  7854.     // Get PCL pointer.
  7855.     pRxDMAData = (PeleAsynchRxDMADataPtr) pFWIMProcessParams->completionProcData;
  7856.  
  7857.     // Add PCL back to active list.
  7858.     PeleFWIMAddAsynchRxDMA (pRxDMAData);
  7859. }
  7860.  
  7861.  
  7862. ////////////////////////////////////////////////////////////////////////////////
  7863. //
  7864. // PeleFWIMProcessWriteResponsePacket
  7865. //
  7866. //   This proc processes a write quadlet response packet.
  7867. //zzz Verify destinationID, and sourceID.
  7868. //
  7869. // NYI - never tested (never happens? same in TIFWIM)
  7870.  
  7871. static void    PeleFWIMProcessWriteResponsePacket(
  7872.     PeleFWIMDataPtr                pPeleFWIMData,
  7873.     PeleAsynchRxDMADataPtr        pRxDMAData,
  7874.     Ptr                            packetBuffer,
  7875.     UInt32                        packetSize)
  7876. {
  7877. //zzz oops, Pele may need this.
  7878. // Pele sends ack_pending to all writes that aren't handled by the physical unit.
  7879. // so we're obligated to send write responses.  But the LynxFWIM may not know what
  7880. // to do with those - it may think the write failed because it only got pending.
  7881. #if 0
  7882.     PeleRegistersPtr            pPeleRegs;
  7883.     FWIMAsynchCommandParamsPtr    pFWIMAsynchCommandParams;
  7884.     UInt32                        *pPacket;
  7885.     UInt32                        commandType;
  7886.     UInt32                        tLabel;
  7887.     AbsoluteTime                timeRemaining;
  7888.     OSStatus                    status = noErr;
  7889. #endif
  7890.  
  7891. //    FWDebugStr ((ConstStr255Param) "\pNYI PeleFWIMProcessWriteResponsePacket");
  7892. #if 0
  7893.     // Get pointer to link registers.
  7894.     pLinkRegs = (TILinkRegistersPtr) (pPeleFWIMData->regBaseAddress +
  7895.                                       kTILinkRegistersOffset);
  7896.  
  7897.     // Read in rest of packet.
  7898.     pPacket = (UInt32 *) packetBuffer;
  7899.     pPacket++;
  7900.     *pPacket++ = EndianSwap32Bit (pLinkRegs->grfData);
  7901.     SynchronizeIO ();
  7902.     *pPacket++ = EndianSwap32Bit (pLinkRegs->grfData);
  7903.     SynchronizeIO ();
  7904.     *pPacket++ = EndianSwap32Bit (pLinkRegs->grfData);
  7905.     SynchronizeIO ();
  7906.     *pPacket++ = EndianSwap32Bit (pLinkRegs->grfData);
  7907.     SynchronizeIO ();
  7908.  
  7909.     pPacket = (UInt32 *) packetBuffer;
  7910.  
  7911.     // Get the pending FWIM command if there is one.
  7912.     pFWIMAsynchCommandParams =
  7913.         (FWIMAsynchCommandParamsPtr) pPeleFWIMData->pPendingFWIMCommand;
  7914.  
  7915.     // We must have a pending write command and a matching transaction label.
  7916.     if (pFWIMAsynchCommandParams != nil)
  7917.     {
  7918.         // Get pending command type and transaction label for this packet.
  7919.         commandType =
  7920.             pFWIMAsynchCommandParams->fwimCommandParams.commandType;
  7921.         tLabel = (pPacket[0] & kPeleAsynchTLabel) >> kPeleAsynchTLabelPhase;
  7922.  
  7923.         if ((commandType == kFWIMWrite) &&
  7924.             (tLabel == pPeleFWIMData->transactionLabel) &&
  7925.             ((pPeleFWIMData->tCode == kFWTCodeWriteQuadlet) ||
  7926.              (pPeleFWIMData->tCode == kFWTCodeWriteBlock)))
  7927.         {
  7928.             // Try to cancel timeout timer.
  7929.             status = CancelTimer (pPeleFWIMData->requestTimeoutTimerID,
  7930.                                   &timeRemaining);
  7931.  
  7932.             // Complete command if we didn't time out.
  7933.             if (status == noErr)
  7934.             {
  7935.                 // Finish up command.
  7936.                 pPeleFWIMData->pPendingFWIMCommand = nil;
  7937.                 status = FWIMCommandIsComplete
  7938.                     (pFWIMAsynchCommandParams->fwimCommandParams.fwimCommandID,
  7939.                      noErr);
  7940.             }
  7941.         }
  7942.     }
  7943. #endif
  7944.  
  7945.     // Add PCL back to active list.
  7946.     PeleFWIMAddAsynchRxDMA (pRxDMAData);
  7947. }
  7948.  
  7949.  
  7950. ////////////////////////////////////////////////////////////////////////////////
  7951. //
  7952. // PeleFWIMProcessReadQuadletPacket
  7953. //
  7954. //   This proc processes a read quadlet packet.
  7955. //
  7956.  
  7957. static void    PeleFWIMProcessReadQuadletPacket(
  7958.     PeleFWIMDataPtr                pPeleFWIMData,
  7959.     PeleAsynchRxDMADataPtr        pRxDMAData,
  7960.     Ptr                            packetBuffer,
  7961.     UInt32                        packetSize)
  7962. {
  7963.     UInt32                        *pPacket = (UInt32 *) packetBuffer;
  7964.     FWIMProcessAsynchParamsPtr    pFWIMProcessAsynchParams;
  7965.     UInt32                        trailerQuad;
  7966.     UInt32                        transactionStatus;
  7967.  
  7968.     // Fill in processing params.
  7969.     pFWIMProcessAsynchParams = &(pRxDMAData->fwimProcessAsynchParams);
  7970.     pFWIMProcessAsynchParams->fwimProcessParams.fwimID = pPeleFWIMData->fwimID;
  7971.     pFWIMProcessAsynchParams->fwimProcessParams.processFlags = 0;
  7972.     pFWIMProcessAsynchParams->fwimProcessParams.completionProc =
  7973.         PeleFWIMProcessReadQuadletRequestCompletionProc;
  7974.     pFWIMProcessAsynchParams->fwimProcessParams.completionProcData = (UInt32) pRxDMAData;
  7975.     pFWIMProcessAsynchParams->timeStamp = UpTime ();//zzz need more accurate time stamp
  7976.     pFWIMProcessAsynchParams->receiveBuffer = (Ptr) &(pPacket[3]);//zzz should probably be nil.
  7977.     pFWIMProcessAsynchParams->generation = pPeleFWIMData->generation;//zzz needs to be more accurate.
  7978.     BlockCopy (packetBuffer,
  7979.                &(pFWIMProcessAsynchParams->destinationID),
  7980.                3 * sizeof (UInt32));
  7981.     pFWIMProcessAsynchParams->length = 4;
  7982.     pFWIMProcessAsynchParams->extendedTCode = 0;
  7983.  
  7984.     trailerQuad = *((UInt32 *) (packetBuffer + packetSize - 4));
  7985.     transactionStatus = ((trailerQuad & kPelePacketAckSent) >> kPelePacketAckSentPhase) <<
  7986.                         kFWTransactionStatusAckCodePhase;
  7987.     transactionStatus |= ((trailerQuad & kPelePacketSpd) >> kPelePacketSpdPhase) <<
  7988.                          kFWTransactionStatusSpeedPhase;
  7989.     pFWIMProcessAsynchParams->transactionStatus = transactionStatus;
  7990.  
  7991.     // Process the read request.
  7992.     FWProcessReadRequest (pFWIMProcessAsynchParams);
  7993. }
  7994.  
  7995.  
  7996. ////////////////////////////////////////////////////////////////////////////////
  7997. //
  7998. // PeleFWIMProcessReadQuadletRequestCompletionProc
  7999. //
  8000. //   This proc will be called upon completion of read request processing.
  8001. //
  8002.  
  8003. static void    PeleFWIMProcessReadQuadletRequestCompletionProc(
  8004.     FWIMProcessParamsPtr        pFWIMProcessParams)
  8005. {
  8006.     PeleAsynchRxDMADataPtr        pRxDMAData;
  8007.  
  8008.     // Get PCL pointer.
  8009.     pRxDMAData = (PeleAsynchRxDMADataPtr) pFWIMProcessParams->completionProcData;
  8010.  
  8011.     // Add PCL back to active list.
  8012.     PeleFWIMAddAsynchRxDMA (pRxDMAData);
  8013. }
  8014.  
  8015.  
  8016. ////////////////////////////////////////////////////////////////////////////////
  8017. //
  8018. // PeleFWIMProcessReadBlockPacket
  8019. //
  8020. //   This proc processes a read block packet.
  8021. //
  8022.  
  8023. static void    PeleFWIMProcessReadBlockPacket(
  8024.     PeleFWIMDataPtr                pPeleFWIMData,
  8025.     PeleAsynchRxDMADataPtr        pRxDMAData,
  8026.     Ptr                            packetBuffer,
  8027.     UInt32                        packetSize)
  8028. {
  8029.     UInt32                        *pPacket = (UInt32 *) packetBuffer;
  8030.     FWIMProcessAsynchParamsPtr    pFWIMProcessAsynchParams;
  8031.     UInt32                        trailerQuad;
  8032.     UInt32                        transactionStatus;
  8033.  
  8034.     // Fill in processing params.
  8035.     pFWIMProcessAsynchParams = &(pRxDMAData->fwimProcessAsynchParams);
  8036.     pFWIMProcessAsynchParams->fwimProcessParams.fwimID = pPeleFWIMData->fwimID;
  8037.     pFWIMProcessAsynchParams->fwimProcessParams.processFlags = 0;
  8038.     pFWIMProcessAsynchParams->fwimProcessParams.completionProc =
  8039.         PeleFWIMProcessReadBlockRequestCompletionProc;
  8040.     pFWIMProcessAsynchParams->fwimProcessParams.completionProcData = (UInt32) pRxDMAData;
  8041.     pFWIMProcessAsynchParams->timeStamp = UpTime ();//zzz need more accurate time stamp
  8042.     pFWIMProcessAsynchParams->receiveBuffer = (Ptr) &(pPacket[4]);//zzz should probably be nil
  8043.     pFWIMProcessAsynchParams->generation = pPeleFWIMData->generation;//zzz needs to be more accurate.
  8044.     BlockCopy (packetBuffer,
  8045.                &(pFWIMProcessAsynchParams->destinationID),
  8046.                4 * sizeof (UInt32));
  8047.  
  8048.     trailerQuad = *((UInt32 *) (packetBuffer + packetSize - 4));
  8049.     transactionStatus = ((trailerQuad & kPelePacketAckSent) >> kPelePacketAckSentPhase) <<
  8050.                         kFWTransactionStatusAckCodePhase;
  8051.     transactionStatus |= ((trailerQuad & kPelePacketSpd) >> kPelePacketSpdPhase) <<
  8052.                          kFWTransactionStatusSpeedPhase;
  8053.     pFWIMProcessAsynchParams->transactionStatus = transactionStatus;
  8054.  
  8055.     // Process the read request.    
  8056.     FWProcessReadRequest (pFWIMProcessAsynchParams);
  8057. }
  8058.  
  8059.  
  8060. ////////////////////////////////////////////////////////////////////////////////
  8061. //
  8062. // PeleFWIMProcessReadBlockRequestCompletionProc
  8063. //
  8064. //   This proc will be called upon completion of read request processing.
  8065. //
  8066.  
  8067. static void    PeleFWIMProcessReadBlockRequestCompletionProc(
  8068.     FWIMProcessParamsPtr        pFWIMProcessParams)
  8069. {
  8070.     PeleAsynchRxDMADataPtr        pRxDMAData;
  8071.  
  8072.     // Get PCL pointer.
  8073.     pRxDMAData = (PeleAsynchRxDMADataPtr) pFWIMProcessParams->completionProcData;
  8074.  
  8075.     // Add PCL back to active list.
  8076.     PeleFWIMAddAsynchRxDMA (pRxDMAData);
  8077. }
  8078.  
  8079.  
  8080. ////////////////////////////////////////////////////////////////////////////////
  8081. //
  8082. // PeleFWIMProcessReadQuadletResponsePacket
  8083. //
  8084. //   This proc processes a read quadlet response packet.
  8085. //zzz Verify destinationID, and sourceID.
  8086. //
  8087.  
  8088. static void    PeleFWIMProcessReadQuadletResponsePacket(
  8089.     PeleFWIMDataPtr                pPeleFWIMData,
  8090.     PeleAsynchRxDMADataPtr        pRxDMAData,
  8091.     Ptr                            packetBuffer,
  8092.     UInt32                        packetSize)
  8093. {
  8094.     FWIMAsynchCommandParamsPtr    pFWIMAsynchCommandParams;
  8095.     UInt32                        *pPacket = (UInt32 *) packetBuffer;
  8096.     UInt32                        commandType;
  8097.     UInt32                        tLabel;
  8098.     UInt32                        rCode;
  8099.     UInt32                        *commandBuffer;
  8100.     AbsoluteTime                timeRemaining;
  8101.     OSStatus                    status = noErr,
  8102.                                 responseStatus = noErr;
  8103.  
  8104. //    FWDebugStr ((ConstStr255Param) "\pPeleFWIMProcessReadQuadletResponsePacket");
  8105.  
  8106.     // Get the pending FWIM command if there is one.
  8107.     pFWIMAsynchCommandParams =
  8108.         (FWIMAsynchCommandParamsPtr) pPeleFWIMData->pPendingFWIMCommand;
  8109.  
  8110.     // We must have a pending read command and a matching transaction label.
  8111.     if (pFWIMAsynchCommandParams != nil)
  8112.     {
  8113.         // Get pending command type, transaction label, and response code for this packet.
  8114.         commandType = pFWIMAsynchCommandParams->fwimCommandParams.commandType;
  8115.         tLabel = (pPacket[0] & kPeleAsynchTLabel) >> kPeleAsynchTLabelPhase;
  8116.         rCode = (pPacket[1] & kPeleAsynchRCode) >> kPeleAsynchRCodePhase;
  8117.  
  8118.         if ((commandType == kFWIMRead) &&
  8119.             (tLabel == pPeleFWIMData->transactionLabel) &&
  8120.             (pPeleFWIMData->tCode == kFWTCodeReadQuadlet))
  8121.         {
  8122.             // Try to cancel timeout timer.
  8123.             status = CancelTimer (pPeleFWIMData->requestTimeoutTimerID,
  8124.                                   &timeRemaining);
  8125.  
  8126.             // Complete command if we didn't time out.
  8127.             if (status == noErr)
  8128.             {
  8129. #if 0            
  8130. sprintf (debugStr, "QRead to %08lx %08lx returns %08lx [rcode %ld]",
  8131.          (long) pFWIMAsynchCommandParams->addressHi,
  8132.          (long) pFWIMAsynchCommandParams->addressLo,
  8133.          (long) pPacket[3],
  8134.          (long) rCode);
  8135. FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  8136. #endif            
  8137.             
  8138.                 // Fill in command buffer.
  8139.                 if (rCode == kFWResponseComplete)
  8140.                 {
  8141.                     commandBuffer = (UInt32 *) pFWIMAsynchCommandParams->buffer;
  8142.                     *commandBuffer = pPacket[3];
  8143.                 }
  8144.                 else
  8145.                 {
  8146.                     responseStatus = accessErr;//zzz not always the best
  8147.                 }
  8148.     
  8149.                 // Finish up command.
  8150.                 pPeleFWIMData->pPendingFWIMCommand = nil;
  8151.                 status = FWIMCommandIsComplete
  8152.                     (pFWIMAsynchCommandParams->fwimCommandParams.fwimCommandID,
  8153.                      responseStatus);
  8154.             }
  8155.         }
  8156.     }
  8157.  
  8158.     // Add PCL back to active list.
  8159.     PeleFWIMAddAsynchRxDMA (pRxDMAData);
  8160. }
  8161.  
  8162.  
  8163. ////////////////////////////////////////////////////////////////////////////////
  8164. //
  8165. // PeleFWIMProcessReadBlockResponsePacket
  8166. //
  8167. //   This proc processes a read block response packet.
  8168. //zzz Verify destinationID, and sourceID.
  8169. //zzz Must check extended tCode.
  8170. //zzz Must return actual number of bytes transferred.
  8171. //
  8172. // NYI - never tested with Pele
  8173.  
  8174. static void    PeleFWIMProcessReadBlockResponsePacket(
  8175.     PeleFWIMDataPtr                pPeleFWIMData,
  8176.     PeleAsynchRxDMADataPtr        pRxDMAData,
  8177.     Ptr                            packetBuffer,
  8178.     UInt32                        packetSize)
  8179. {
  8180.     FWIMAsynchCommandParamsPtr    pFWIMAsynchCommandParams;
  8181.     UInt32                        *pPacket = (UInt32 *) packetBuffer;
  8182.     UInt32                        commandType;
  8183.     UInt32                        tLabel;
  8184.     UInt32                        rCode;
  8185.     UInt32                        dataLength;
  8186.     AbsoluteTime                timeRemaining;
  8187.     OSStatus                    status = noErr,
  8188.                                 responseStatus = noErr;
  8189.  
  8190. //zzz should check ackSent to see if the packet was OK...?
  8191.  
  8192. //    FWDebugStr ((ConstStr255Param) "\pPeleFWIMProcessReadBlockResponsePacket");
  8193.  
  8194.     dataLength = (((UInt32 *) packetBuffer)[3] & kPeleAsynchDataLength) >>
  8195.                   kPeleAsynchDataLengthPhase;
  8196.     
  8197.     // Get the pending FWIM command if there is one.
  8198.     pFWIMAsynchCommandParams =
  8199.         (FWIMAsynchCommandParamsPtr) pPeleFWIMData->pPendingFWIMCommand;
  8200.  
  8201.     // We must have a pending read command and a matching transaction label.
  8202.     if (pFWIMAsynchCommandParams != nil)
  8203.     {
  8204.         // Get pending command type, transaction label, and response code for this packet.
  8205.         commandType = pFWIMAsynchCommandParams->fwimCommandParams.commandType;
  8206.         tLabel = (pPacket[0] & kPeleAsynchTLabel) >> kPeleAsynchTLabelPhase;
  8207.         rCode = (pPacket[1] & kPeleAsynchRCode) >> kPeleAsynchRCodePhase;
  8208.  
  8209.         if ((commandType == kFWIMRead) &&
  8210.             (tLabel == pPeleFWIMData->transactionLabel) &&
  8211.             (pPeleFWIMData->tCode == kFWTCodeReadBlock))
  8212.         {
  8213.             // Try to cancel timeout timer.
  8214.             status = CancelTimer (pPeleFWIMData->requestTimeoutTimerID,
  8215.                                   &timeRemaining);
  8216.  
  8217.             // Complete command if we didn't time out.
  8218.             if (status == noErr)
  8219.             {
  8220.                 // Fill in command buffer.
  8221.                 if (rCode == kFWResponseComplete)
  8222.                 {
  8223.                     if (dataLength > pFWIMAsynchCommandParams->length)
  8224.                         dataLength = pFWIMAsynchCommandParams->length;
  8225.                     BlockCopy (&(pPacket[4]),
  8226.                                pFWIMAsynchCommandParams->buffer,
  8227.                                dataLength);
  8228.                 }
  8229.                 else
  8230.                 {
  8231.                     responseStatus = accessErr;//zzz not always the best
  8232.                 }
  8233.  
  8234.                 // Finish up command.
  8235.                 pPeleFWIMData->pPendingFWIMCommand = nil;
  8236.                 status = FWIMCommandIsComplete
  8237.                     (pFWIMAsynchCommandParams->fwimCommandParams.fwimCommandID,
  8238.                      responseStatus);
  8239.             }
  8240.         }
  8241.     }
  8242.  
  8243.     // Add PCL back to active list.
  8244.     PeleFWIMAddAsynchRxDMA (pRxDMAData);
  8245. }
  8246.  
  8247.  
  8248. ////////////////////////////////////////////////////////////////////////////////
  8249. //
  8250. // PeleFWIMProcessLockPacket
  8251. //
  8252. //   This proc processes a lock packet.
  8253. //
  8254.  
  8255. static void    PeleFWIMProcessLockPacket(
  8256.     PeleFWIMDataPtr                pPeleFWIMData,
  8257.     PeleAsynchRxDMADataPtr        pRxDMAData,
  8258.     Ptr                            packetBuffer,
  8259.     UInt32                        packetSize)
  8260. {
  8261.     UInt32                        *pPacket = (UInt32 *) packetBuffer;
  8262.     FWIMProcessAsynchParamsPtr    pFWIMProcessAsynchParams;
  8263.     UInt32                        trailerQuad;
  8264.     UInt32                        transactionStatus;
  8265.  
  8266.     // Fill in processing params.
  8267.     pFWIMProcessAsynchParams = &(pRxDMAData->fwimProcessAsynchParams);
  8268.     pFWIMProcessAsynchParams->fwimProcessParams.fwimID = pPeleFWIMData->fwimID;
  8269.     pFWIMProcessAsynchParams->fwimProcessParams.processFlags = 0;
  8270.     pFWIMProcessAsynchParams->fwimProcessParams.completionProc =
  8271.         PeleFWIMProcessLockRequestCompletionProc;
  8272.     pFWIMProcessAsynchParams->fwimProcessParams.completionProcData = (UInt32) pRxDMAData;
  8273.     pFWIMProcessAsynchParams->timeStamp = UpTime ();//zzz need more accurate time stamp
  8274.     pFWIMProcessAsynchParams->receiveBuffer = (Ptr) &(pPacket[4]);//zzz receive and transmit buffers should be different
  8275.     pFWIMProcessAsynchParams->generation = pPeleFWIMData->generation;//zzz needs to be more accurate.
  8276.     BlockCopy (packetBuffer,
  8277.                &(pFWIMProcessAsynchParams->destinationID),
  8278.                4 * sizeof (UInt32));
  8279.  
  8280.     trailerQuad = *((UInt32 *) (packetBuffer + packetSize - 4));
  8281.     transactionStatus = ((trailerQuad & kPelePacketAckSent) >> kPelePacketAckSentPhase) <<
  8282.                         kFWTransactionStatusAckCodePhase;
  8283.     transactionStatus |= ((trailerQuad & kPelePacketSpd) >> kPelePacketSpdPhase) <<
  8284.                          kFWTransactionStatusSpeedPhase;
  8285.     pFWIMProcessAsynchParams->transactionStatus = transactionStatus;
  8286.  
  8287.     // Process the lock request.
  8288.     FWProcessLockRequest (pFWIMProcessAsynchParams);
  8289. }
  8290.  
  8291.  
  8292. ////////////////////////////////////////////////////////////////////////////////
  8293. //
  8294. // PeleFWIMProcessLockRequestCompletionProc
  8295. //
  8296. //   This proc will be called upon completion of lock request processing.
  8297. //
  8298.  
  8299. static void    PeleFWIMProcessLockRequestCompletionProc(
  8300.     FWIMProcessParamsPtr        pFWIMProcessParams)
  8301. {
  8302.     PeleAsynchRxDMADataPtr        pRxDMAData;
  8303.  
  8304.     // Get PCL pointer.
  8305.     pRxDMAData = (PeleAsynchRxDMADataPtr) pFWIMProcessParams->completionProcData;
  8306.  
  8307.     // Add PCL back to active list.
  8308.     PeleFWIMAddAsynchRxDMA (pRxDMAData);
  8309. }
  8310.  
  8311.  
  8312. ////////////////////////////////////////////////////////////////////////////////
  8313. //
  8314. // PeleFWIMProcessLockResponsePacket
  8315. //
  8316. //   This proc processes a lock response packet.
  8317. //zzz Verify destinationID, and sourceID.
  8318. //zzz Must check extended tCode.
  8319. //
  8320. // (IRM sends these)
  8321.  
  8322. static void    PeleFWIMProcessLockResponsePacket(
  8323.     PeleFWIMDataPtr                pPeleFWIMData,
  8324.     PeleAsynchRxDMADataPtr        pRxDMAData,
  8325.     Ptr                            packetBuffer,
  8326.     UInt32                        packetSize)
  8327. {
  8328.     FWIMAsynchCommandParamsPtr    pFWIMAsynchCommandParams;
  8329.     UInt32                        *pPacket = (UInt32 *) packetBuffer;
  8330.     UInt32                        commandType;
  8331.     UInt32                        tLabel;
  8332.     UInt32                        rCode;
  8333.     UInt32                        dataLength;
  8334.     AbsoluteTime                timeRemaining;
  8335.     OSStatus                    status = noErr,
  8336.                                 responseStatus = noErr;
  8337.  
  8338. //    FWDebugStr ((ConstStr255Param) "\pPeleFWIMProcessLockResponsePacket");
  8339.  
  8340.     dataLength = (pPacket[3] & kPeleAsynchDataLength) >> kPeleAsynchDataLengthPhase;
  8341.     if (dataLength & 0x03)
  8342.         dataLength = (dataLength & 0xFFFFFFFC) + 4;
  8343.  
  8344.     // Get the pending FWIM command if there is one.
  8345.     pFWIMAsynchCommandParams =
  8346.         (FWIMAsynchCommandParamsPtr) pPeleFWIMData->pPendingFWIMCommand;
  8347.  
  8348.     // We must have a pending lock command and a matching transaction label.
  8349.     if (pFWIMAsynchCommandParams != nil)
  8350.     {
  8351.         // Get pending command type, transaction label, and response code for this packet.
  8352.         commandType = pFWIMAsynchCommandParams->fwimCommandParams.commandType;
  8353.         tLabel = (pPacket[0] & kPeleAsynchTLabel) >> kPeleAsynchTLabelPhase;
  8354.         rCode = (pPacket[1] & kPeleAsynchRCode) >> kPeleAsynchRCodePhase;
  8355.  
  8356.         if ((commandType == kFWIMLock) &&
  8357.             (tLabel == pPeleFWIMData->transactionLabel) &&
  8358.             (pPeleFWIMData->tCode == kFWTCodeLock))
  8359.         {
  8360.             // Try to cancel timeout timer.
  8361.             status = CancelTimer (pPeleFWIMData->requestTimeoutTimerID,
  8362.                                   &timeRemaining);
  8363.  
  8364.             // Complete command if we didn't time out.
  8365.             if (status == noErr)
  8366.             {
  8367.                 // Fill in command buffer.
  8368.                 if (rCode == kFWResponseComplete)
  8369.                 {
  8370.                     if (dataLength > pFWIMAsynchCommandParams->length)
  8371.                         dataLength = pFWIMAsynchCommandParams->length;
  8372.                     BlockCopy (&(pPacket[4]),
  8373.                                pFWIMAsynchCommandParams->buffer,
  8374.                                dataLength);
  8375.                 }
  8376.                 else
  8377.                 {
  8378.                     responseStatus = accessErr;//zzz not always the best
  8379.                 }
  8380.     
  8381.                 // Finish up command.
  8382.                 pPeleFWIMData->pPendingFWIMCommand = nil;
  8383.                 status = FWIMCommandIsComplete
  8384.                     (pFWIMAsynchCommandParams->fwimCommandParams.fwimCommandID,
  8385.                      responseStatus);
  8386.             }
  8387.         }
  8388.     }
  8389.  
  8390.     // Add PCL back to active list.
  8391.     PeleFWIMAddAsynchRxDMA (pRxDMAData);
  8392. }
  8393.  
  8394.  
  8395. static void PeleFWIMFireBugMsg (
  8396.     PeleFWIMDataPtr                pPeleFWIMData,
  8397.     char                         *msg)
  8398. {
  8399.     UInt32                        sourceID;
  8400.  
  8401.     sourceID = EndianSwap32Bit (pPeleFWIMData->pPeleRegisters->nodeID << 16);
  8402.     
  8403.     PeleFWIMWriteAT (pPeleFWIMData, kFWSpeed100MBit, 4,
  8404.                       0x42420010, sourceID, 0x0, (strlen (msg) + 1) << 16,
  8405.                       strlen (msg) + 1, (UInt32 *) msg);
  8406. }
  8407.  
  8408.  
  8409. /////////////////////////
  8410. //  End of PeleFWIM.c  //
  8411. /////////////////////////